Stage 4: Modern Java, lesson 5 of 7

Pattern matching: instanceof, switch and record patterns

Advanced3 min read@since 22Code runs on your Java 25
Explain it forThe essentials plus production detail and pitfalls.

Pattern matching tests a value's shape and pulls out its parts in one step.

  • instanceof patterns (final in Java 16): if (obj instanceof String s), with no cast needed.
  • switch patterns (final in Java 21): switch on types, with guards (when) and case null.
  • Record patterns (final in Java 21): take a record apart right inside the pattern.
  • Unnamed variables _ (final in Java 22) for the parts you don't need.

Combined with sealed interfaces, the compiler checks that every case is handled.

Old way vs new way

Before Java 16
if (e instanceof Purchase) {
    Purchase p = (Purchase) e;
    if (p.amountInr() > 5000) return "Big sale: " + p.course();
    return "Sale: " + p.course();
} else if (e instanceof Signup) {
    return "Welcome mail to " + ((Signup) e).email();
}
// easy to forget a type: the compiler can't help
Java 21+ pattern switch
sealed interface Event permits Signup, Purchase, Refund {}
record Signup(String email) implements Event {}
record Purchase(String course, int amountInr) implements Event {}
record Refund(String course, int amountInr, String reason) implements Event {}

String describe(Event e) {
    return switch (e) {
        case Signup(var email)                        -> "Welcome mail to " + email;
        case Purchase(var c, var amt) when amt > 5000 -> "Big sale: " + c;
        case Purchase(var c, _)                       -> "Sale: " + c;     // _ is Java 22+
        case Refund(var c, var amt, _)                -> "Refund " + amt + " for " + c;
    };
}

Object o = 42;
if (o instanceof Integer i && i > 40) {          // Java 16+
    System.out.println(i + 1);
}

Common mistake

Adding a default branch to a switch over a sealed type. It compiles, but you lose the compile error that would tell you when someone adds a new subtype.

Under the hood

Pattern cases are checked for dominance: putting a broad case (case Purchase p) before a narrower guarded one is a compile error. Primitive type patterns (case int i when i > 0) have been in preview since Java 23, now in their fifth preview in Java 27. This style is Java's take on algebraic data types, familiar from Scala and Kotlin.

Check yourself

Which version made pattern matching for switch final?

How this connects

Where this leads

You've reached the end of this thread. Try a learning path for what's next.

Part of Upgrade from Java 8 to Java 25.

Was this lesson helpful?

Finished reading? Mark it complete to track your progress.