is Java's automatic conversion between (, ) and their (, ). It's convenient but has subtle pitfalls — performance overhead, surprising behavior, and risk.
intdoubleIntegerDouble==NullPointerExceptionInteger boxed = 42; // autoboxing: int → Integer (Integer.valueOf(42))
int unboxed = boxed; // auto-unboxing: Integer → int (boxed.intValue())
List<Integer> nums = new ArrayList<>();
nums.add(5); // autoboxes int 5 → Integer (collections need objects)
int x = nums.get(0); // auto-unboxes Integer → int
It happens automatically because collections and generics require objects (you can't have List<int>), so Java boxes primitives transparently.
Integer a = 1000;
Integer b = 1000;
a == b; // ❌ FALSE — different Integer OBJECTS (reference comparison)
a.equals(b); // ✅ true — value comparison
// the WORSE trap — the Integer cache makes small values seem to work:
Integer c = 100, d = 100;
c == d; // TRUE — Java CACHES Integers from -128 to 127 (same object)
Integer e = 200, f = 200;
e == f; // FALSE — outside the cache range → different objects
This is insidious: == on Integer works for small values (cached) but fails for large ones — code that seems correct in testing breaks in production. Always use .equals() for wrapper value comparison, or unbox to primitives first.
Integer value = null; // a wrapper can be null
int x = value; // 💥 NullPointerException — unboxing null calls null.intValue()
Map<String, Integer> map = new HashMap<>();
int count = map.get("missing"); // 💥 NPE — get() returns null, then unboxing fails
Unboxing a null wrapper throws an NPE — a common, surprising crash, especially with map lookups that return null.
// ❌ autoboxing in a hot loop — creates millions of Integer objects (GC pressure, slow)
Long sum = 0L; // WRONG type — wrapper
for (long i = 0; i < 1_000_000; i++) {
sum += i; // unbox, add, re-box → new Long each iteration!
}
// ✅ use primitives in hot paths
long sum = 0L; // primitive — no boxing
Repeated boxing/unboxing creates excessive objects, hurting performance in tight loops.
Autoboxing is convenient and pervasive (collections, generics all rely on it), but its pitfalls cause real, hard-to-diagnose bugs.
The == trap is especially dangerous: comparing Integers with == works for cached small values (-128 to 127) but silently fails for larger ones — a bug that passes tests and breaks in production — making .equals() (or unboxing) essential for wrapper comparison. NullPointerExceptions from unboxing null wrappers (common with map lookups) are another frequent crash.
And boxing in hot loops creates needless objects, hurting performance.
Understanding when boxing happens, the value-vs-reference comparison issue, the null-unboxing risk, and using primitives in performance-critical code is important for writing correct, efficient Java — and the Integer-cache == behavior is a classic interview question that reveals deep understanding.