Autoboxing and Unboxing in Java
Before Java 5, putting a number in a list meant writing list.add(Integer.valueOf(91)), and reading it back meant list.get(0).intValue(). Now you just write list.add(91) and int m = list.get(0). Autoboxing is the compiler converting a primitive to its wrapper automatically; unboxing is the reverse. It's convenient, but the conversions are still there in the bytecode, with a cost and a trap.
Boxing and Unboxing in Action
import java.util.ArrayList;
import java.util.List;
public class Boxing {
public static void main(String[] args) {
List<Integer> marks = new ArrayList<>();
marks.add(91);
int first = marks.get(0);
Integer bonus = 5;
int total = first + bonus;
System.out.println(total);
}
}96How it works
marks.add(91): the list needs anInteger, so91is boxed.int first = marks.get(0): theIntegeris unboxed to anint.Integer bonus = 5: boxing again.first + bonus: arithmetic needs primitives, sobonusis unboxed.
What the Compiler Really Writes
javap -c shows the hidden method calls:
11: invokestatic #10 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
30: invokevirtual #26 // Method java/lang/Integer.intValue:()I
35: invokestatic #10 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
41: invokevirtual #26 // Method java/lang/Integer.intValue:()IBoxing is Integer.valueOf(x); unboxing is x.intValue(). That's all autoboxing is: the compiler writing these calls for you.
Where Conversions Happen
| Situation | Conversion |
|---|---|
Assigning a primitive to a wrapper: Integer x = 5; | Boxing |
Passing a primitive where an object is expected: list.add(5) | Boxing |
Arithmetic or comparison with <, >: x + 1, x > 3 | Unboxing |
Assigning a wrapper to a primitive: int y = x; | Unboxing |
x++ on an Integer | Unbox, add, box a new Integer |
A ternary mixing int and Integer | Often unboxes the wrapper |
The null Traps
Unboxing a null wrapper calls a method on null. The most common case is reading a missing key from a map:
import java.util.HashMap;
import java.util.Map;
public class Npe {
public static void main(String[] args) {
Map<String, Integer> marks = new HashMap<>();
marks.put("Navika", 91);
int m = marks.get("Advitha");
}
}Exception in thread "main" java.lang.NullPointerException: Cannot invoke "java.lang.Integer.intValue()" because the return value of "java.util.Map.get(Object)" is null
at Npe.main(Npe.java:8)marks.get("Advitha") returns null, and assigning it to an int calls intValue() on it. The helpful message names the exact call. Fixes: marks.getOrDefault("Advitha", 0), or keep the result as an Integer and check it.
A sneakier version hides in the conditional operator: Integer applied = member ? 10 : discount; throws when discount is null, because the mix of int and Integer makes the whole expression an int, which unboxes discount.
Common Mistakes
Unboxing a value that might be null. Check first, or use getOrDefault.
Using wrapper types for loop counters and sums. Use int and long.
Comparing two Integer objects with ==. Boxing doesn't make == compare values (see "Integer Cache in Java").
Interview Corner
What are autoboxing and unboxing?
Autoboxing is the automatic conversion of a primitive to its wrapper object, such as int to Integer, when an object is required. Unboxing is the reverse, when a primitive is required. The compiler implements them with calls to valueOf and intValue-style methods. They were introduced in Java 5.
Can unboxing cause a NullPointerException?
Yes. Unboxing calls a method such as intValue() on the wrapper, so if the wrapper is null, a NullPointerException is thrown. Common sources are map.get for a missing key and conditional expressions that mix primitives and wrappers.
Practice
- Easy: Store five scores in a
List<Integer>, then add them up into aninttotal using a for-each loop. Which lines box and which unbox? - Harder: Fix
Npe.javatwo ways: withgetOrDefault, and by keeping the result as anIntegerand printing "not found" when it's null.
Key Takeaways
Was this tutorial helpful?