skip to content

How does instanceof pattern matching behave with null, and what are common pitfalls when relying on it as a null check?

level: middleimportance: should knowfreq 40%

answer

  1. null instanceof T → always false
  2. Bound variable always non-null in scope
  3. Negative branch = null OR wrong type
  4. switch patterns still NPE without case null
  5. Don't add redundant null check on the binding

basics

~20 s

null instanceof Type t is always false, so the pattern variable is never bound for null — instanceof gives you a free null check. The pitfall: switch pattern matching changed null handling, and don't assume the variable is non-null without the test passing.

solid answer

~50 s

For `instanceof`, null never matches any type: `null instanceof String s` is false and `s` is not bound. This means an instanceof pattern is implicitly null-safe — if `obj instanceof String s` is true, `s` is guaranteed non-null inside the matched region, so you never get a NullPointerException from using it there. A common pitfall is carrying intuition from this into `switch` pattern matching, where the rules differ: a traditional `switch` throws NPE on a null selector, but a switch with patterns can include an explicit `case null` (and you can write `case null, default`), so null behavior is opt-in and easy to get wrong. Another pitfall is assuming the negative branch means 'obj is null' — it actually means 'obj is null OR not a String'. So `if (!(obj instanceof String s))` covers both null and wrong-type cases, which is usually what you want but worth stating precisely.

go deeper

for a junior

Knows null instanceof Type is false and that the bound variable is never null.

for a middle

Explains the free null-guard, that the negative branch means null-or-wrong-type, and that the variable needs no null check.

for a senior

Contrasts instanceof null behavior with switch pattern matching's NPE-unless-case-null rule and reasons about distinguishing null from wrong type.

for a principal

Sets conventions around null handling across instanceof and switch patterns, especially for sealed hierarchies, and avoids surprising NPEs in dispatch code.

## Null and instanceof: the core rule In Java, `null instanceof AnyType` is **always false** — and this has been true since long before pattern matching. The pattern form inherits this exactly: ```java String obj = null; if (obj instanceof String s) { // false, because obj is null // never entered; s is never bound } ``` Because the variable `s` is only bound when the test is true, and the test is false for null, **`s` is guaranteed non-null** wherever it's in scope. So an instanceof pattern is effectively a combined **null check + type check + cast**: ```java if (obj instanceof String s && s.length() > 0) { ... } // reaching s.length() means obj was non-null AND a String ``` This is genuinely useful: it replaces the older three-line `if (obj != null && obj instanceof String) { String s = (String) obj; ... }` with one expression (the explicit null check was always redundant, but the pattern makes the safety obvious). ## Pitfall 1: the negative branch covers TWO cases ```java if (!(obj instanceof String s)) { // obj is null OR obj is not a String } ``` Don't read the false branch as 'obj is null'. It is 'null **or** wrong type'. Usually that's exactly the guard you want, but if you need to distinguish null from a wrong-type object, you must test null separately. ## Pitfall 2: carrying the rule into switch pattern matching This is the big one. A *traditional* `switch` (on an enum or String) **throws NullPointerException** if the selector is null. **Switch pattern matching** (a separate feature) changes the landscape: ```java String s = ...; switch (s) { case null -> System.out.println("was null"); // explicit null case allowed case "x" -> ...; default -> ...; } ``` - Without a `case null`, a pattern switch still **throws NPE** on null (preserving compatibility). - With `case null` (or the combined `case null, default`), null is handled explicitly. The pitfall is assuming "patterns are null-safe like instanceof" and forgetting that a pattern *switch* still NPEs on null unless you add `case null`. The null-safety is an `instanceof`-operator property, not a blanket pattern-matching property. ## Pitfall 3: assuming the bound variable could be null The opposite mistake: adding a redundant `if (s != null)` inside the matched region. Since the match excludes null, that check is dead code and signals a misunderstanding. ## Summary - `instanceof` pattern: null never matches → variable is always non-null in scope → free null guard. - Negative branch = null OR wrong type. - `switch` patterns: still NPE on null unless you write `case null`. ## Terms recap - **NullPointerException (NPE)**: thrown when dereferencing null. - **selector**: the value a `switch` evaluates. - **case null**: explicit null branch allowed only in pattern (and some recent) switches. - **null guard**: code preventing use of a null value.

  • Does a pattern switch over a sealed interface throw if the selector is null?
    Yes, unless it has a `case null` (or `case null, default`). Pattern switches preserve the traditional NPE-on-null behavior by default; null handling is opt-in.
  • How would you distinguish a null obj from a wrong-type obj?
    Test null first: `if (obj == null) { ... } else if (obj instanceof String s) { ... } else { /* wrong type */ }`. The instanceof negative branch alone collapses null and wrong-type into one path.

saying these in an interview costs you the question

  • Claiming null matches instanceof patterns
  • Reading the false branch as 'obj is null' only
  • Assuming switch patterns are automatically null-safe
  • Adding a redundant null check on a bound pattern variable

context