Free Java Tutorials >> Table of contents >> Primitives

1. Primitive Types and Precision

Primitive Types

Java has 8 primitive types that are built into the language specification: byte, short, int, long, float, double, boolean, and char. All other types (such as String) are supplied via libraries, some of which are included with Java when you download the JRE or JDK. The primitives are:

  • byte: The byte type is an 8-bit signed two's complement integer. The range of a byte goes from -128 to 127. It may be useful to use bytes to save memory compared to an int.

  • short: The short type is a 16-bit signed two's complement integer. The range of a short goes from -32,768 to 32,767 .

  • int: The int type is a 32-bit signed two's complement integer. The default range is two to the power of 31 (minus 1) to negative two to the power of 31. Advanced programmers should note that in Java 8, int can also represent unsigned 32-bit integers. These have a range from 0 to 2 to the power of 32 (minus 1). See the documentation on Integer and Number for more information about how to perform operations on unsigned integers.

  • long: The long type is a 64-bit two's complement integer. The signed long has a minimum value of -2 to the power of 63 and a maximum value of 2 to the power of 63 (minus 1). Like int, Java 8 now supports unsigned longs.

  • float: The float type is a single-precision 32-bit IEEE 754 floating point.

  • double: The double type is a double-precision 64-bit IEEE 754 floating point.

  • boolean: The boolean type has only two possible values: true and false. Note that unlike C++, true is not equivalent to 1, and false is not equivalent to 0.

  • char: The char type is a single 16-bit Unicode character. We will discuss the char type in more detail when we learn about Strings.

Floating Point Precision

Floating point numbers do not perfectly represent decimal values from math. You can imagine these numbers as being written on a short piece of paper, and so trailing values far right of the decimal point are often lost. The numbers are presented in binary with a variable number of whole number digits. Thus, numbers that seem round (like 1.3) may actually stored only approximately. Java will often round numbers when printing, so you cannot assume that two floating point numbers are equivalent.

These examples uses material from later sections:

public class MyProgram {
    public static void main(String[] args) {
		double a = 0.7;
		double b = 0.9;
		double x = a + 0.1; //0.8
		double y = b - 0.1; //0.8
		
		//The == operator can be used to compare two numbers:
		System.out.println(x == y); //Prints false
		//x and y are not equal, even though they would be in math.
    }
}

Advanced programmers should instead subtract two numbers and check whether the difference is small enough.

public class MyProgram {
    public static void main(String[] args) {
		double a = 0.7;
		double b = 0.9;
		double x = a + 0.1; //0.8
		double y = b - 0.1; //0.8
		
		System.out.println(x == y); //Prints false
		
		//Math.abs is absolute value:
		System.out.println(Math.abs(x - y) < 0.0001); //Prints true
    }
}

Use double rather than float when you need more precision. For arbitrarily high precision, research the BigDecimal class in Java.

2. More Expression Literals

Binary, Octal, and Hexadecimal

By default, integer expressions are in decimal. For example, 10 is the number ten. However, see these examples:

  • Binary can be written as 0b10. The "0b", a zero-b, means that 0b10 is binary 10 (or two). Binary types are by default ints. You can cast them like so: (byte)0b10101, to get a byte. For very long binary values, append "L" to the end to get a long value.
  • Octal can be written as 010. The preceding 0 makes the expression base 8, so 010 is equal to eight in decimal. The same type conversion rules from binary apply to octal
  • Hexadecimal can be written as 0x10. The preceding 0x makes the expression base 16. The same type conversion rules from binary apply.
public class MyProgram {
    public static void main(String[] args) {
		int x = 0b10 * 010; //2 * 8 = 16;
		System.out.println(x);
		int y = 0x10 - 0b10; //16 - 2 = 14;
		System.out.println(y);
    }
}

Primitive type literals

You can also force certain numerical expressions into a type:

  • long can be forced with an L, such as 123L
  • float can be forced with an f, such as 1.2f
  • double can be forced with an d, such as 1.2d

3. Overflow, Underflow, and NaN

Maximum and Minimal Values

Integer types all have maximum and minimal values:

public class MyProgram {
    public static void main(String[] args) {
		System.out.println(Byte.MIN_VALUE);
		System.out.println(Byte.MAX_VALUE);
		System.out.println(Short.MIN_VALUE);
		System.out.println(Short.MAX_VALUE);
		System.out.println(Integer.MIN_VALUE);
		int x = Integer.MAX_VALUE;
		System.out.println(x);
		System.out.println(Long.MIN_VALUE);
		System.out.println(Long.MAX_VALUE);
    }
}

You might ask. What happens when you subtract one from the minimum value or add one to the maximum value? The answer is an underflow (for too low) or an overflow for too high. Integer.MIN_VALUE - 1 is equal to Integer.MAX_VALUE. In other words, the integer "wraps around" from the smallest to largest values. Research how two's complement notation causes this effect.

Floating point types also have minimum and maximum values, but their behavior is not within the scope of this textbook.

NaN and Infinity

If you divide an integer value by zero, the application will crash with an ArithmeticException. However, if you divide a floating point number by zero, your program will not crash. Instead, the decimal will equal either Infinity or NaN, which stands for Not A Number. Here are some examples:

public class MyProgram {
    public static void main(String[] args) {
		System.out.println(Double.POSITIVE_INFINITY);
		System.out.println(Double.NEGATIVE_INFINITY);
		System.out.println(1.0/0.0); //Infinity
		System.out.println(1.0/0.0 + 2.0); //Infinity
		System.out.println(1.0/0.0 * 0.2); //Infinity
		System.out.println(1.0/0.0 * 0.0); //NaN
		
		System.out.println(1.0/0.0 - 1.0/0.0); //NaN
		System.out.println(1.0/0.0 / (1.0/0.0)); //NaN
		System.out.println(int)(1.0/0.0)); //same as Integer.MAX_VALUE
    }
}

Note also that NaN is not equal to itself.

Negative zero

Some floating point operations result in -0.0, which is a number that is very close to zero but negative. Some special cases occur when using -0.0:

public class MyProgram {
    public static void main(String[] args) {
		System.out.println(-0.0 == 0.0); //true
		System.out.println(1.0 / 0.0);   //Infinity
		System.out.println(1.0 / -0.0);  //-Infinity
    }
}

Advanced programmers should note that -0.0 >= 0 is false, so special care must be used when comparing floating point values to zero.

4. Bitwise Operators

Binary Representation

Integers are stored in binary. For example, the byte type uses 8 bits, and (byte)0 is represent internally as binary 00000000 . In two's complement notation, the first bit is used to represent the sign of a number. Thus, 0b1111111 is the largest number (127). You may wish to review binary before proceeding.

Often, we want to perform operations on individual bits themselves rather the number as a whole:

  • Bit fields (flags): Sometimes we want each bit of a number to represent whether an option is enabled or disabled. For example 00000001 may represent "turn on READ feature", while 00000000 may represent turn off the read feature. Similarly, 00000010 may represent "turn on WRITE feature". Thus, 00000011 may represent turning on both read and write.
  • Combinatorics: We can use binary to represent whether an object is included or not included in a set. For example 111 may represent a red ball, a green ball, and a blue ball. 101 may represent just a red and blue ball. Thus all combinations are represented by the numbers 000 to 111.
  • Graphics: Some graphics processing applications heavily use bit operators.
  • Network applications: Different portions of a long bit stream may represent different things, such as the from-IP address, checksum (to ensure the data was correctly set), and other information. We may want to extract certain bits out of a longer number and perform operations on just those.
  • Compression: While standard (ASCII) text uses a fixed number of bits per character, compressed data may use bits in a more fluid manner.
  • Binary Executables: Assembly code run by the CPU or virtual machine often uses portions of a larger bit stream to represent the command. Other portions may represent arguments, parameters, and other information.

Bit operators

There are seven bitwise operators in Java:

  • ~ : Unary bitwise complement, which takes one number (to the right). This flips all the bits so that 0's becomes 1's and 1's become 0. Note that for signed numbers such as int, this also negates the number.
  • << : Signed left shift. This operator takes two numbers. It shifts the number to the left by the number of bits on the right. For example 5<<1 equals 10, because 0b101 becomes 0b1010. This also has the same effect as multiplying the left side by a power of 2.
  • >> : Signed right shift. Like the signed left shift, bytes are shifted by the right argument. Both signed left and signed right do not affect the first bit (the sign bit). 0b1010 shifted right by 1 becomes 0b101
  • >>> : Unsigned right shift. This will shift all bits right by the argument amount. Note that this also shifts the leftmost bit (the sign bit).
  • & : Bitwise AND. This takes two numbers and returns a number. The output is true when the corresponding bits of both inputs are true. For example 0b110 AND 0b011 becomes 0b010, since the middle bit is true for both.
  • ^ : Bitwise exclusive OR (XOR) : This takes two numbers and returns a number. The output is true when exactly one of the corresponding input bits are true. For example, 0b110 XOR 0b010 is 0b100, since only the first bit is different between the two inputs.
  • | : Bitwise inclusive OR : This takes two numbers and returns a number. The output is true when either of the corresponding input bits are true. For example, 0b110 OR 0b010 is 0b110. Only the rightmost bit is zero since it is zero in both inputs.

Previous: Arithmetic

Next: Booleans