From Effective Java 2/e by Joshua Bloch
Three differences
- Primitives have only their values, whereas boxed primitives have identities distinct from their values
- Primitive types have only fully functional values, whereas each boxed primitive type has one nonfunctional value which is null
- Primitives are generally more time- and space-efficient than boxed primitives
Example #1
// naturalOrder.compare(new Integer(42), new Integer(42)) == 1 (should be 0) Comparator<Integer> naturalOrder = new Comparator<Integer>() { public int compare(Integer first, Integer second) { return first < second ? -1 : (first == second ? 0 : 1); } }; // naturalOrder.compare(new Integer(42), new Integer(42)) == 0 Comparator<Integer> naturalOrder = new Comparator<Integer>() { public int compare(Integer first, Integer second) { int f = first; // Auto-unboxing int s = second; // Auto-unboxing return f < s ? -1 : (f == s ? 0 : 1); // No unboxing } };
Example #2
// It throws a NullPointerException when evaluating the expression (i == 42) public class Unbelievable { static Integer i; public static void main(String[] args) { if (i == 42) System.out.println("Unbelievable"); } }
In nearly every case when you mix primitives and boxed primitives in a single operation, the boxed primitive is auto-unboxed
Example #3
// Hideously slow program! Can you spot the object creation? public static void main(String[] args) { Long sum = 0L; for (long i = 0; i < Integer.MAX_VALUE; i++) { sum += i; } System.out.println(sum); }
Conclusion
- Autoboxing reduces the verbosity, but not the danger, of using boxed primitives
- When your program does mixed-type computations involving boxed and unboxed primitives, it does unboxing, and when your program does unboxing, it can throw a NullPointerException