skip to content

How can autoboxing introduce a NullPointerException, and where does this commonly bite?

level: middleimportance: should knowfreq 63%

answer

  1. Unboxing null = null.intValue() → NPE
  2. NPE shows up with no visible method call → confusing
  3. Map.get, nullable DB/JSON fields are top sources
  4. Ternary mixing wrapper+primitive unboxes whole expression
  5. Fix: prefer primitives, getOrDefault, requireNonNullElse, null-check

basics

~20 s

Unboxing 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 s

Unboxing 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

for a junior

Knows that unboxing a null Integer throws an NPE and that Map.get can return null.

for a middle

Explains it compiles to null.intValue(), enumerates the common sources (maps, DB, JSON, ternaries), and uses getOrDefault/requireNonNullElse defenses.

for a senior

Recognizes the implicit-unbox-the-whole-ternary rule, designs nullability at boundaries, and relies on static analysis to catch nullable unboxing.

for a principal

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

context