Java 8 Pocket Guide (2014)
Part I. Language
Chapter 3. Fundamental Types
Fundamental types include the Java primitive types and their corresponding wrapper classes/reference types. Java 5.0 and beyond provide for automatic conversion between these primitive and reference types through autoboxing and unboxing. Numeric promotion is applied to primitive types where appropriate.
Primitive Types
There are eight primitive types in Java; each is a reserved keyword. They describe variables that contain single values of the appropriate format and size; see Table 3-1. Primitive types are always the specified precision, regardless of the underlying hardware precisions (e.g., 32- or 64-bit).
Table 3-1. Primitive types
Type |
Detail |
Storage |
Range |
boolean |
true or false |
1 bit |
Not applicable |
char |
Unicode character |
2 bytes |
\u0000 to \uFFFF |
byte |
Integer |
1 byte |
–128 to 127 |
short |
Integer |
2 bytes |
–32768 to 32767 |
int |
Integer |
4 bytes |
–2147483648 to 2147483647 |
long |
Integer |
8 bytes |
–263 to 263 –1 |
float |
Floating point |
4 bytes |
1.4e–45 to 3.4e+38 |
double |
Floating point |
8 bytes |
5e–324 to 1.8e+308 |
TIP
Primitive types byte, short, int, long, float, and double are all signed. Type char is unsigned.
Literals for Primitive Types
All primitive types except boolean can accept character, decimal, hexadecimal, octal, and Unicode literal formats, as well as character escape sequences. Where appropriate, the literal value is automatically cast or converted. Remember that bits are lost during truncation. The following is a list of primitive assignment examples:
boolean isTitleFight = true;
The boolean primitive’s only valid literal values are true and false.
char [] cArray = {'\u004B', 'O', '\'', 0x0064, 041,(char) 131105, 0b00100001}; // KO'd!!!
The char primitive represents a single Unicode character. Literal values of the char primitive that are greater than two bytes need to be explicitly cast.
byte rounds = 12, fighters = (byte) 2;
The byte primitive has a four-byte signed integer as its valid literal. If an explicit cast is not performed, the integer is implicitly cast to one byte.
short seatingCapacity = 17157, vipSeats = (short) 500;
The short primitive has a four-byte signed integer as its valid literal. If an explicit cast is not performed, the integer is implicitly cast to two bytes.
int ppvRecord = 19800000, vs = vipSeats, venues = (int) 20000.50D;
The int primitive has a four-byte signed integer as its valid literal. When char, byte, and short primitives are used as literals, they are automatically cast to four-byte integers, as in the case of the short value within vipSeats. Floating-point and long literals must be explicitly cast.
long wins = 38L, losses = 4l, draws = 0, knockouts = (long) 30;
The long primitive uses an eight-byte signed integer as its valid literal. It is designated by an L or l postfix. The value is cast from four bytes to eight bytes when no postfix or cast is applied.
float payPerView = 54.95F, balcony = 200.00f, ringside = (float) 2000, cheapSeats = 50;
The float primitive has a four-byte signed floating point as its valid literal. An F or f postfix or an explicit cast designates it. Even though no explicit cast is necessary for an int literal, an int will not always fit into a float where the value exceeds about 2^23.
double champsPay = 20000000.00D, challengersPay = 12000000.00d, chlTrainerPay = (double) 1300000, refereesPay = 3000, soda = 4.50;
The double primitive uses an eight-byte signed floating-point value as its valid literal. The literal can have a D, d, or explicit cast with no postfix. If the literal is an integer, it is implicitly cast.
See Chapter 2 for more details on literals.
Floating-Point Entities
Positive and negative floating-point infinities, negative zero, and Not-a-Number (NaN) are special entities defined to meet the IEEE 754-1985 standard; see Table 3-2.
The Infinity, –Infinity, and –0.0 entities are returned when an operation creates a floating-point value that is too large to be traditionally represented.
Table 3-2. Floating-point entities
Entity |
Description |
Examples |
Infinity |
Represents the concept of positive infinity |
1.0 / 0.0, 1e300 / 1e–300, Math.abs (–1.0 / 0.0) |
–Infinity |
Represents the concept of negative infinity |
–1.0 / 0.0, 1.0 / (–0.0), 1e300/–1e–300 |
–0.0 |
Represents a negative number close to zero |
–1.0 / (1.0 / 0.0), –1e–300 / 1e300 |
NaN |
Represents undefined results |
0.0 / 0.0, 1e300 * Float.NaN, Math.sqrt (–9.0) |
Positive infinity, negative infinity, and NaN entities are available as double and float constants:
Double.POSITIVE_INFINITY; // Infinity
Float.POSITIVE_INFINITY; // Infinity
Double.NEGATIVE_INFINITY; // –Infinity
Float.NEGATIVE_INFINITY; // –Infinity
Double.NaN; // Not-a-Number
Float.NaN; // Not-a-Number
The Double and Float wrapper classes have methods to determine if a number is finite, infinite, or NaN:
Double.isFinite(Double.POSITIVE_INFINITY); // false
Double.isFinite(Double.NEGATIVE_INFINITY); // false
Double.isFinite(Double.NaN); // false
Double.isFinite(1); // true
Double.isInfinite(Double.POSITIVE_INFINITY); // true
Double.isInfinite(Double.NEGATIVE_INFINITY); // true
Double.isInfinite(Double.NaN); // false
Double.isInfinite(1); // false
Double.isNaN(Double.NaN); // true
Double.isNaN(1); // false
Operations Involving Special Entities
Table 3-3 shows the results of special entity operations where the operands are abbreviated as INF for Double.POSITIVE_INFINITY, –INF for Double.NEGATIVE_INFINITY, and NAN for Double.NaN.
For example, column 4’s heading entry (–0.0) and row 12’s entry (\* NAN) have a result of NaN, and could be written as follows:
// 'NaN' will be printed
System.out.print((-0.0) * Double.NaN);
Table 3-3. Operations involving special entities
INF |
(–INF) |
(–0.0) |
|
* INF |
Infinity |
–Infinity |
NaN |
+ INF |
Infinity |
NaN |
Infinity |
– INF |
NaN |
–Infinity |
–Infinity |
/ INF |
NaN |
NaN |
–0.0 |
* 0.0 |
NaN |
NaN |
–0.0 |
+ 0.0 |
Infinity |
–Infinity |
0.0 |
+ 0.5 |
Infinity |
–Infinity |
0.5 |
* 0.5 |
Infinity |
–Infinity |
–0.0 |
+ (–0.5) |
Infinity |
–Infinity |
–0.5 |
* (–0.5) |
–Infinity |
Infinity |
0.0 |
+ NAN |
NaN |
NaN |
NaN |
* NAN |
NaN |
NaN |
NaN |
TIP
Any operation performed on NaN results in NaN; there is no such thing as –NaN.
Numeric Promotion of Primitive Types
Numeric promotion consists of rules that are applied to the operands of an arithmetic operator under certain conditions. Numeric promotion rules consist of both unary and binary promotion rules.
Unary Numeric Promotion
When a primitive of a numeric type is part of an expression, as listed in Table 3-4, the following promotion rules are applied:
§ If the operand is of type byte, short, or char, the type will be promoted to type int.
§ Otherwise, the type of the operand remains unchanged.
Table 3-4. Expression for unary promotion rules
Expression |
Operand of a unary plus operator |
Operand of a unary minus operator – |
Operand of a bitwise complement operator ~ |
All shift operators >>, >>>, or << |
Index expression in an array access expression |
Dimension expression in an array creation expression |
Binary Numeric Promotion
When two primitives of different numerical types are compared via the operators listed in Table 3-5, one type is promoted based on the following binary promotion rules:
§ If either operand is of type double, the non-double primitive is converted to type double.
§ If either operand is of type float, the non-float primitive is converted to type float.
§ If either operand is of type long, the non-long primitive is converted to type long.
§ Otherwise, both operands are converted to int.
Table 3-5. Operators for binary promotion rules
Operators |
Description |
+ and – |
Additive operators |
*, /, and % |
Multiplicative operators |
<, ⇐, >, and >= |
Comparison operators |
== and != |
Equality operators |
&, ^, and | |
Bitwise operators |
? : |
Conditional operator (see next section) |
Special Cases for Conditional Operators
§ If one operand is of type byte and the other is of type short, the conditional expression will be of type short:
short = true ? byte : short
§ If one operand R is of type byte, short, or char, and the other is a constant expression of type int whose value is within range of R, the conditional expression is of type R:
short = (true ? short : 1967)
§ Otherwise, binary numeric promotion is applied and the conditional expression type will be that of the promoted type of the second and third operands.
Wrapper Classes
Each of the primitive types has a corresponding wrapper class/reference type, which is located in package java.lang. Each wrapper class has a variety of methods, including one to return the type’s value, as shown in Table 3-6. These integer and floating-point wrapper classes can return values of several primitive types.
Table 3-6. Wrapper classes
Primitive types |
Reference types |
Methods to get primitive values |
boolean |
Boolean |
booleanValue() |
char |
Character |
charValue() |
byte |
Byte |
byteValue(), shortValue(), intValue(), longValue(), floatValue(), doubleValue() |
short |
Short |
byteValue(), shortValue(), intValue(), longValue(), floatValue(), doubleValue() |
int |
Integer |
byteValue(), shortValue(), intValue(), longValue(), floatValue(), doubleValue() |
long |
Long |
byteValue(), shortValue(), intValue(), longValue(), floatValue(), doubleValue() |
float |
Float |
byteValue(), shortValue(), intValue(), longValue(), floatValue(), doubleValue() |
double |
Double |
byteValue(), shortValue(), intValue(), longValue(), floatValue(), doubleValue() |
Autoboxing and Unboxing
Autoboxing and unboxing are typically used for collections of primitives. Autoboxing involves the dynamic allocation of memory and initialization of an object for each primitive. Note that the overhead can often exceed the execution time of the desired operation. Unboxing involves the production of a primitive for each object.
Computationally intensive tasks using primitives (e.g., iterating through primitives in a container) should be done using arrays of primitives in preference to collections of wrapper objects.
Autoboxing
Autoboxing is the automatic conversion of primitive types to their corresponding wrapper classes. In this example, the prizefighter’s weight of 147 is automatically converted to its corresponding wrapper class because collections store references, not primitive values:
// Create hash map of weight groups
HashMap<String, Integer> weightGroups
= new HashMap<String, Integer> ();
weightGroups.put("welterweight", 147);
weightGroups.put("middleweight", 160);
weightGroups.put("cruiserweight", 200);
The following example shows an acceptable but not recommended use of autoboxing:
// Establish weight allowance
Integer weightAllowanceW = 5; //improper
TIP
For these examples, wrapper class variables end with a capital W. This is not the convention.
As there is no reason to force autoboxing, the preceding statement should instead be written as follows:
Integer weightAllowanceW = new Integer (5);
Unboxing
Unboxing is the automatic conversion of the wrapper classes to their corresponding primitive types. In this example, a reference type is retrieved from the hash map. It is automatically unboxed so that it can fit into the primitive type:
// Get the stored weight limit
int weightLimitP = weightGroups.get(middleweight);
TIP
For these examples, primitive variables end with a capital P. This is not the convention.
The following example shows an acceptable but not recommended use of unboxing:
// Establish the weight allowance
weightLimitP = weightLimitP + weightAllowanceW;
It is better to write this expression with the intValue() method, as shown here:
weightLimitP = weightLimitP
+ weightAllowanceW.intValue(
);