Literals
Any constant value that can be assigned to a variable is called a literal.
Integral literals
import java.lang.*;
class Test {
public static void main(String[] args) {
// decimal form literals: (base 10)
int x = 10;
// octal form literals: (base 8)
// note: to make JVM treat the number as octal, prefix the number with '0'.
int x = 010;
// Hexadecimal form literals: (base 16)
// note: to make JVM treat a number as hexadecimal, prefix the number with "0x".
int x = 0x10;
}
}
For integral data types (byte, short, int, long), we can specify literal values in the following ways:
decimal | octal | hexadecimal | |
---|---|---|---|
base | 10 | 8 | 16 |
allowed values | 0-9 | 0-7 | 0-9, a-f |
prefix | n/a | 0 | 0x |
These are the only possible ways to specify literal values for integral data types.
Java is case sensitive, however for using hexadecimal characters a-f or 'x' in the prefix, both upper and lower case characters are allowed. This is one of very few areas where Java is not case sensitive:
import java.lang.*;
class Test {
public static void main(String[] args) {
int x = 10; // VALID
int x = 0786; // INVALID: integer value too large compile-time error
int x = 0777; // VALID
int x = 0XFace; // VALID
int x = 0xBeef; // VALID
int x = 0xBeer; // INVALID: ';' expected (instead of 'r') compile-time error
}
}
A programmer has the choice to provide a integral literal in decimal, octal and hexadecimal format, but the JVM will always return the value in decimal form:
import java.lang.*;
class Test {
public static void main(String[] args) {
int x = 10;
int y = 010;
int z = 0x10;
System.out.println(x); // 10
System.out.println(y); // 0 * 8⁰ + 1 * 8¹ = 8
System.out.println(z); // 0 * 16⁰ + 1 * 16¹ = 16
}
}
Every integral literal is by default an "int" data type. To explicity specify as long type by adding 'l' or 'L' suffix to the value:
import java.lang.*;
class Test {
public static void main(String[] args) {
int x = 10; // VALID
long l = 10L; // VALID
int y = 10L; // INVALID: possible loss of precision, found: long, required int
long z = 10; // VALID
}
}
There is no way to explicitly specify a byte or short data type by using 'b', 'B' for byte and 's' or 'S' for short. However, we can indirectly infer the type of a "byte" and "short" data type by using correct data type:
import java.lang.*;
class Test {
public static void main(String[] args) {
byte x = 10; // VALID
byte l = 127; // VALID
byte y = 128; // INVALID: possible loss of precision, found: int, required byte
short a = 32767; // VALID
short c = 32768; // INVALID: possible loss of precision, found: int, required short
}
}
If an integral literal value is assigned to a byte variable, and if the value of the literal is within the range of byte, then the compiler automatically treats it as a byte variable. The same rule applies to short data type, if an integral literal value is assgined to a short variable, and the value of the literal is within the range of short, then the compiler automatically treats it as a short variable.
Floating-point literals
By default every floating point literal is of double data type, hence we can't assign directly to a float variable. However we can specify floating point literal as float data type by using suffix 'F' or 'f':
import java.lang.*;
class Test {
public static void main(String[] args) {
float a = 123.256; // INVALID: possible loss of precision, found: double, required float
float b = 123.456F; // VALID
double c = 123.456; // VALID
double d = 123.456D; // VALID
}
}
By default every floating point literal is of double data type, but we can still explicitly specify as "double" data type by using suffix 'd' or 'D'. This convention is not required because by default it is already "double" data type:
import java.lang.*;
class Test {
public static void main(String[] args) {
double d = 123.456D; // VALID
float f = 123.256D; // INVALID: possible loss of precision, found: double, required float
}
}
We can specify floating point literals can only be specified in decimal form and we can't specify in octal and hexadecimal form:
import java.lang.*;
class Test {
public static void main(String[] args) {
double a = 123.456; // VALID
double b = 0123.456; // VALID - treated as decimal value (123.456)
double c = 0x123.456; // INVALID: malformed floating point literal compile time error
}
}
We can assign integral literal directly to floating-point variables and that integral literal can be specified either in decimal, or hexadecimal or octal forms:
import java.lang.*;
class Test {
public static void main(String[] args) {
double a = 0786; /*INVALID - integer number too large compile time error
(treated as octal integral, but wrong because 8 is not allowed as octal value)*/
double b = 0xFace; // VALID - treated as decimal value (64206.0)
double c = 0786.0; // VALID - treated as decimal value (786.0)
double d = 0xFace.0; // INVALID - we can't specify floating-point value in hexadecimal form
double e = 10; // VALID - (10.0)
double f = 0777; // VALID - (511.0)
}
}
We can't assign floating point literals to integral types:
import java.lang.*;
class Test {
public static void main(String[] args) {
double a = 10; // VALID
int b = 10.0; // INVALID - posibble loss of precision compile time error, found: double, required: int
}
}
We can specify floating-point literal even in exponential form (scientific notation):
import java.lang.*;
class Test {
public static void main(String[] args) {
double a = 1.2e3; // VALID (1.2*10³ = 1.2*1000 = 1200.0)
float b = 1.2e3; // INVALID - possible loss of precision compile time error, found: double, required: float
float b = 1.2e3F; // VALID
}
}
Boolean literals
The only values allowed for "boolean" data types are "true" or "false".
import java.lang.*;
class Test {
public static void main(String[] args) {
boolean a = true; // VALID
boolean b = 0; // INVALID - incompatible types compile time error, found: int, required: boolean
boolean c = True; // INVALID - cannot find symbol compile time error, symbol: variable True, location: class Test
boolean d = "true"; // INVALID - incompatible types compile time error, found: String, required: boolean
}
}
import java.lang.*;
class Test {
public static void main(String[] args) {
int x = 0;
if(x) { // incompatible types compile time error, found: int, required: boolean
System.out.println("Hello");
} else {
System.out.println("Hi");
}
while(1) { // incompatible types compile time error, found: int, required: boolean
System.out.println("Hello");
}
}
}
The example above would be valid in C or C++; where any value >0 is considered true, and any value <=0 is considered false.
Char literals
There are several ways to specify a literal value for character literal.
Specifying char literal a single character within single quotes
We can specify char literal as single character within single quotes:
import java.lang.*;
class Test {
public static void main(String[] args) {
char a = 'a'; // VALID
char b = a; // INVALID - cannot find symbol compile time error, symbol: variable a, location: class Test
char c = "a"; // INVALID - incompatible types compile time error, found j.l.String, required: char
char d = 'ab'; // INVALID - unclosed char literal CTE twice(for each char) and not a statement CTE
}
}
Specifying char literal as integral literal
Each character has a corresponding unicode value. We can specify char literal as integral literal which represents unicode value of that character. The integral literal can be specified in octal, hexadecimal or decimal forms. The allowed range for the integral literal should be 0 - 65535:
import java.lang.*;
class Test {
public static void main(String[] args) {
char a = 97; // VALID
char b = 0xFace; // VALID
char c = 0777; // VALID
char d = 65535; // VALID
char e = 65536; // INVALID - CTE: possible loss of precision, found: int, required: char
}
}
When printing char literals that are specified using integral, sometimes a '?' will be displayed, this is because the required font to display that character may not be installed in the system. To check the correspondig character, see unicode.org
Specifying char literal in unicode representation
We can represent char literals in unicode representation ('\uxxxx' - 4 digit hexadecimal number):
import java.lang.*;
class Test {
public static void main(String[] args) {
char a = '\u0061'; // VALID - unicode value for 'a'
char b = '\u0062'; // VALID - unicode value for 'b'
}
}
Specifying char literal as escape character
Every escape character is a char literal:
import java.lang.*;
class Test {
public static void main(String[] args) {
char a = '\n'; // VALID
char b = '\t'; // VALID
char c = '\m'; // INVALID - Illegal escape character CTE
}
}
There are a total of 8 escape characters in Java.
Escape character | Description |
---|---|
\n | new line |
\t | horizontal tab |
\r | carriage return |
\b | backspace |
\f | form feed |
\' | single quote |
\" | double quote |
\\ | backslash |
import java.lang.*;
class Test {
public static void main(String[] args) {
System.out.println("' is a quote"); // INVALID
System.out.println("\' is a quote"); // VALID
System.out.println("" is a double quote"); // INVALID
System.out.println("\" is a double quote"); // VALID
System.out.println("\ is a backslash"); // INVALID
System.out.println("\\ is a backslash"); // VALID
}
}
import java.lang.*;
class Test {
public static void main(String[] args) {
char a = 65536; // INVALID - 65536 out of range
char b = 0XBeer; // INVALID - 'r' is not a hexadecimal value
char c = \uface; // INVALID - single quotes are missing
char d = '\ubeef'; // VALID
char e = '\m'; // INVLID - illegal escape character
char f = '\iface'; // INVALID \i not valid
}
}
String literals
Any sequence of characters within double quotes is treated as a string literal.
import java.lang.*;
class Test {
public static void main(String[] args) {
String a = "durga";
}
}
1.7 enhancement with respect to literals
Binary literals
From Java 1.7 we can also specify integral literals in binary form. To specify a number a binary, it has to be prefixed with "0B" or "0b" and only contain 0's and 1's.
import java.lang.*;
class Test {
public static void main(String[] args) {
int a = 0B1111;
int b = 0b1011;
}
}
Therefore, until Java 1.6, there were only three ways (decimal, hexadecimal and octal) to specify integral values, but from Java 1.7, with the addition of binary literals, we could specify integrals in four different ways (binary, decimal, hexadecimal and octal)
Usage of underscore withing digits of numeric literals
Another enhancement of literals in Java 1.7 is usage of underscore character between digits of numberic literals. The main advantage of this approach is code readability is improved. At the time of compilation, the underscore characters will be removed automatically, hence after compilation the values will be as though they never had the underscore characters.
import java.lang.*;
class Test {
public static void main(String[] args) {
long a = 1_234_567_890L; // after compilation: 1234567890
int b = 1_234_567; // after compilation: 1234567
double c = 1_234_567.0_9_8_7; // after compilation: 1234567.0987
}
}
We can use more than one underscore character between the digits if required to make code even more readable.
import java.lang.*;
class Test {
public static void main(String[] args) {
long a = 1__234__567__890L; // after compilation: 1234567890
int b = 1__234__567; // after compilation: 1234567
double c = 1__234__567.0__9__8__7; // after compilation: 1234567.0987
}
}
We can use underscore character only between the digits. If underscore character is used anywhere else, we will get a compile time error.
import java.lang.*;
class Test {
public static void main(String[] args) {
long a = _1__234__567__890L; // INVALID
int b = 1__234__567_; // INVALID
double c = 1__234__567_.0__9__8__7; // INVALID
}
}
Summary
We can assign lower data type value to higher data type variable.
8-byte long value can be assigned to 4-byte float variable because both are following different memory representations internally.
import java.lang.*;
class Test {
public static void main(String[] args) {
float a = 10L;
System.out.println(a); // 10.0
}
}
Even though short and char are both 2 bytes, they cannot be assigned to each other interchangeably, because short is signed, and byte is unsigned. Meaning they accept different range values, short accepts range -32,768 to 32,767, and char accepts range 0 to 65535.