Wrapper classes
Every primitive type has a wrapper class — a class whose object holds one value of that type: int → Integer, double → Double, boolean → Boolean, char → Character (plus Long, Short, Byte and Float). Wrappers are needed wherever Java accepts only objects: in collections and in generic types.
An object instead of a number
Integer.valueOf() packs a number into an object, and intValue() takes it back out:
void main() {
Integer box = Integer.valueOf(42);
int number = box.intValue();
IO.println(box);
IO.println(number + 1);
}Output:
42
43The other wrappers name their methods the same way: Double.valueOf() and doubleValue(), Boolean.valueOf() and booleanValue().
Autoboxing and unboxing
You almost never have to call these methods by hand. Java packs a primitive into an object by itself (autoboxing) and unpacks the object back (unboxing) whenever the types do not match:
void main() {
Integer count = 5;
int next = count + 1;
List<Double> prices = new ArrayList<>();
prices.add(9.99);
double first = prices.get(0);
IO.println(next);
IO.println(first);
}Output:
6
9.99In count + 1 the object was unboxed to an int, and in prices.add(9.99) the number was boxed into a Double. Lists and maps are covered in detail in the collections chapter — for now it is enough to know that they hold only objects.
Useful methods
Wrappers are also toolboxes of ready-made methods for their type. You already know Integer.parseInt() from the type conversion lesson; here are some others:
void main() {
IO.println(Integer.MAX_VALUE);
IO.println(Integer.compare(3, 7));
IO.println(Character.isDigit('7'));
IO.println(Character.isLetter('q'));
IO.println(Character.toUpperCase('q'));
IO.println(Boolean.parseBoolean("true"));
}Output:
2147483647
-1
true
true
Q
trueInteger.compare(a, b) returns a negative number, zero or a positive number depending on which number is larger.
null instead of a value
A primitive variable always holds a number, but a wrapper variable can hold null — "no value". This is handy when a missing value is different from zero:
void main() {
Integer bonus = null;
IO.println("Bonus: " + bonus);
}Output:
Bonus: nullComparing with ==
For objects, == checks whether it is the same object, not whether the values are equal. Java creates Integer objects for the numbers from −128 to 127 in advance and reuses them — this is the Integer cache. So for small numbers == happens to work, and for larger ones it does not:
void main() {
Integer a = 127;
Integer b = 127;
IO.println(a == b);
Integer c = 128;
Integer d = 128;
IO.println(c == d);
IO.println(c.equals(d));
}Output:
true
false
trueCompare the values of wrappers with equals() or unbox them to int first.
Common mistake
Unboxing null crashes the program with a NullPointerException. This happens most often with a map: get() returns null for a missing key, and an int variable cannot accept it:
void main() {
Map<String, Integer> stock = Map.of("apples", 10);
int pears = stock.get("pears");
IO.println(pears);
}Output:
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "java.lang.Integer.intValue()" because the return value of "java.util.Map.get(Object)" is nullUse stock.getOrDefault("pears", 0), or store the result in an Integer variable and check it for null.