Pattern Matching (instanceof & switch)
Pattern matching lets instanceof and switch test a value's type and bind it to a ready-to-use, correctly typed variable in a single step — no separate cast required.
Learn Pattern Matching (instanceof & switch) in our free Java course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a…
Part of the free Java course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
You should know inheritance and casting and the new switch expressions . instanceof patterns need Java 16+ ; switch patterns need Java 21+ .
💡 Analogy: The old way was like a mailroom worker who first checks "is this a parcel?" and then, in a separate step, picks up the parcel to weigh it ( if (o instanceof Box) {" Box b = (Box) o; ... "} ). Pattern matching is the worker who recognises the parcel and already has it in hand: if (o instanceof Box b) — one motion. A pattern switch is the sorting table where each chute is labelled by type , and whatever lands there arrives already identified.
The win is fewer casts, fewer chances to cast to the wrong type, and code that reads as "when it's a String named s , do this".
Write the type test and a variable name together: o instanceof String s . If o is a String , the binding variable s is in scope and already typed — call s.length() with no cast. Compare the before/after:
A pattern switch dispatches on the type of its selector. Each case Type name -> ... matches when the value is that type and binds name . This collapses a tower of if/else instanceof checks into one tidy switch. Add an explicit case null so a null selector is handled instead of throwing.
A guard adds a boolean condition to a pattern using when : case String s when s.isEmpty() -> ... . The arm matches only if the type matches and the guard is true. Because arms are tried top to bottom, list the most specific guarded patterns first and the plain pattern last as a catch-all for that type.
Predict the result before opening each answer.
Answer: No. Outside the if , the pattern isn't provably true, so s is out of scope: error: cannot find symbol s . Use s only where the match holds.
Answer: This won't compile. The plain case Integer i comes first and matches every Integer , so the guarded arm below is unreachable — a compile error. Swap their order.
Answer: If obj is null , it throws NullPointerException — a pattern switch only handles null if you add case null . Add case null -> "none"; to be safe.
🎯 Your Turn — instanceof with a binding
Combine a pattern with && to only match long strings, and handle integers too.
🧩 Mini-Challenge — A grading pattern switch
Use guarded patterns and a case null label — and get the order right.
You can now bind a typed variable straight from instanceof , dispatch on type with a pattern switch , refine matches with when guards, handle null with case null , and order cases so the first match is the right one.
Next up: Sealed Classes & Interfaces — restrict who may implement a type so a pattern switch can be exhaustive.
Practice quiz
What does if (o instanceof String s) give you?
- A boolean only
- A test plus a String variable s already cast
- A new String object
- Nothing useful
Answer: A test plus a String variable s already cast. Pattern matching for instanceof tests the type AND binds s as a String in one step — no explicit cast.
Inside the body where the pattern matched, do you still need to cast?
- Yes, always
- No — the binding variable is already the matched type
- Only for primitives
- Only in switch
Answer: No — the binding variable is already the matched type. The binding variable is automatically the narrowed type, so the old (String) o cast disappears.
In a switch, what is case String s -> ... called?
- A constant label
- A type pattern
- A guard
- A default
Answer: A type pattern. Matching by type and binding a variable in switch is a type pattern.
What keyword adds a boolean condition to a switch pattern?
- if
- where
- when
- guard
Answer: when. A guarded pattern uses when: case Integer i when i > 100 -> ...
How do you handle null in a pattern switch so it doesn't throw?
- It is handled by default automatically
- Add an explicit case null -> ... label
- Wrap in try/catch
- Use Optional
Answer: Add an explicit case null -> ... label. A traditional switch throws on null; a pattern switch lets you add case null to handle it safely.
Does a traditional switch (no patterns) throw on a null selector?
- No
- Yes, NullPointerException
- It returns null
- It skips to default
Answer: Yes, NullPointerException. A classic switch throws NullPointerException on null unless you guard it beforehand; pattern switch can add case null.
Where can you use the binding variable from a guarded pattern?
- Only in the guard
- Only in the body
- In both the when guard and the arm body
- Nowhere
Answer: In both the when guard and the arm body. The pattern variable is in scope for the guard and the arm body.
In which Java version did pattern matching for instanceof become standard?
- Java 8
- Java 14
- Java 16
- Java 21
Answer: Java 16. instanceof pattern matching finalized in Java 16 (JEP 394).
When did pattern matching for switch become a standard feature?
- Java 16
- Java 17
- Java 21
- Java 8
Answer: Java 21. Pattern matching for switch was finalized in Java 21 (JEP 441).
Why must a more specific guarded case come BEFORE a broader one?
- Style only
- Cases are tried top to bottom; the first match wins
- The compiler reorders them
- It does not matter
Answer: Cases are tried top to bottom; the first match wins. A pattern switch checks arms in order, so put specific/guarded patterns before the general fallback.