How can autoboxing introduce a NullPointerException, and where does this commonly bite?
answer
- Unboxing null = null.intValue() → NPE
- NPE shows up with no visible method call → confusing
- Map.get, nullable DB/JSON fields are top sources
- Ternary mixing wrapper+primitive unboxes whole expression
- Fix: prefer primitives, getOrDefault, requireNonNullElse, null-check
basics
~20 sUnboxing a null wrapper throws a NullPointerException. If an Integer is null and you assign it to an int, compare with ==, or do arithmetic on it, Java calls null.intValue() and crashes. Common with map lookups, nullable DB columns, and ternary expressions.
solid answer
~50 sUnboxing compiles to a method call like Integer.intValue(). If the wrapper reference is null, that call is invoked on null and throws a NullPointerException — but the NPE appears at a spot where there's no visible method call, so it's confusing. The classic triggers: assigning a nullable Integer to an int; arithmetic or comparison on a possibly-null wrapper (`if (count > 0)` when count is null); a ternary that mixes a wrapper and a primitive (`flag ? null : 0` unboxes the whole expression to int, NPE on the null branch). It bites most with Map.get (returns null for absent keys), nullable columns from JDBC/ORM, JSON deserialization producing null wrappers, and Optional misuse. Defenses: prefer primitives so the value can't be null, null-check before unboxing, use a default (Objects.requireNonNullElse or `map.getOrDefault(k, 0)`), and be wary of conditional expressions that force unboxing.
go deeper
Knows that unboxing a null Integer throws an NPE and that Map.get can return null.
Explains it compiles to null.intValue(), enumerates the common sources (maps, DB, JSON, ternaries), and uses getOrDefault/requireNonNullElse defenses.
Recognizes the implicit-unbox-the-whole-ternary rule, designs nullability at boundaries, and relies on static analysis to catch nullable unboxing.
Establishes nullability conventions and annotations across the codebase, integrates Error Prone/SpotBugs gates, and minimizes wrapper use in domain models to make the bug class unrepresentable.
## Why unboxing a null throws Unboxing is the compiler inserting a call like `someInteger.intValue()`. If `someInteger` is `null`, that's a method call on a null reference → **NullPointerException**. The trap is that your source code shows no `.intValue()` and often no obvious dereference — just an assignment or an arithmetic operator — so the NPE seems to come from nowhere. ```java Map<String, Integer> counts = ...; int c = counts.get("missing"); // get returns null → null.intValue() → NPE ``` ## The common bite points 1. **`Map.get`** returns `null` for absent keys. Assigning that to an `int`, or doing `counts.get(k) + 1`, unboxes null. 2. **Nullable database columns.** JDBC `ResultSet.getInt` returns 0 for SQL NULL (its own footgun), but ORMs/mappers often map a nullable column to an `Integer` field that is then unboxed elsewhere. 3. **JSON / deserialization.** A missing or `null` JSON field deserializes to a `null` wrapper; later arithmetic unboxes it. 4. **Ternary / conditional expressions.** If one branch is a wrapper and the other a primitive, Java unboxes the *whole* expression to the primitive type. `boolean b; Integer x = null; int y = b ? 0 : x;` — if `b` is false, this unboxes `x` (null) → NPE. Even `b ? x : 0` is at risk because the result type is `int`. 5. **Arithmetic/comparison on nullable wrappers.** `if (nullableInteger > 0)`, `nullableLong + 1`, `value == 5` (where `value` is a null `Integer`) all unbox. 6. **Stream/collection sums** where an element is a null Integer. ## Defenses - **Prefer primitives** wherever null isn't a legitimate value — a primitive *cannot* be null, so the whole class of bug disappears. - **Null-check before unboxing**, or supply a default: `int c = counts.getOrDefault(k, 0);`, `Objects.requireNonNullElse(x, 0)`. - **Be explicit about nullability** — annotate fields/params (`@Nullable`/`@NonNull`) and let static analysis (SpotBugs, IDE inspections, Error Prone) flag unboxing of nullable values. - **Watch ternaries** — make both branches the same boxed type, or null-check first, to avoid the implicit unbox-the-whole-expression rule. - **Validate at boundaries** (deserialization, DB mapping) so nulls don't flow deep into arithmetic. ## Why this is an autoboxing topic The NPE is a *direct consequence* of the implicit primitive↔wrapper conversion: the convenience that lets a wrapper act like a primitive also lets `null` masquerade as a number until the unbox call detonates. Understanding boxing is understanding when this conversion silently happens.
- Does `ResultSet.getInt` for a SQL NULL throw or return 0?It returns 0 (and you must call wasNull() to distinguish). That's the opposite footgun: it silently hides the null. The NPE problem comes from getObject/ORM mapping to an Integer that is later unboxed. Both stem from mismatches between nullable database values and non-null primitives.
- How does a ternary like `cond ? someInteger : 0` cause an NPE?The conditional operator computes a single result type. Mixing Integer and int makes the result type int, so the chosen branch is unboxed. If someInteger is null and cond is true, it unboxes null → NPE — even though the literal 0 branch looks safe.
saying these in an interview costs you the question
- Thinking unboxing null silently yields 0 (that's ResultSet.getInt, not unboxing)
- Not realizing a ternary can unbox the whole expression and NPE on the null branch
- Blaming the NPE on the wrong line because no .intValue() is visible
- Catching the NPE instead of preventing the null/unbox