← Back to Advanced Java Course | Chapter 4: Modern Java Features | Lesson 5 of 12

Java Pattern Matching

Pattern matching lets you check a type and grab its parts in one step, like opening a package and checking its label at once. It replaces long check-and-cast code.
Syntax
java
if (object instanceof Type variable) {
    // use variable
}

switch (object) {
    case Type variable -> expression;
    default -> expression;
}

Pattern Matching with instanceof

Pattern matching for instanceof simplifies the classic type-check-then-cast pattern by combining both steps into a single expression. Instead of checking instanceof and then separately casting on the next line, the matched, correctly-typed variable is bound automatically as part of the check itself.

Example: Pattern Matching with instanceof

java
public class Main {
	public static void main(String[] args) {
		Object obj = "hello";
		if (obj instanceof String s) { // bound and cast in one step
			System.out.println(s.toUpperCase());
		}
	}
}

Pattern Variable Scope

A pattern variable introduced by pattern matching is only considered in scope in the branches of code where the type check is statically guaranteed to have succeeded. This prevents you from accidentally referencing an unset or wrongly-typed variable outside that guaranteed region.

Example: Pattern Variable Scope

java
public class Main {
	public static void main(String[] args) {
		Object obj = "text";
		if (obj instanceof String s && s.length() > 2) {
			System.out.println(s); // s is only in scope where the check succeeded
		}
	}
}

Pattern Matching in Switch

Pattern matching can also be used inside switch statements and switch expressions, letting a single switch match a variable against several different classes and automatically cast it to the matched type inside each corresponding case.

Example: Pattern Matching in Switch

java
// Define the class Main
public class Main {
	static String describe(Object obj) {
		// Send switch (obj) { back to the caller
		return switch (obj) {
			case Integer i -> "Integer: " + i;
			case String s -> "String: " + s;
			default -> "Unknown";
		};
	}
	// Program entry point: the JVM starts running here
	public static void main(String[] args) {
		// Print a line to the console
		System.out.println(describe(42));
	}
}

Switch Patterns with Guards

You can attach conditional checks, called guards, to individual switch cases using the when keyword. This lets you filter within a single pattern-matched case, for example matching a specific class but only when one of its fields also satisfies an extra condition.

Example: Switch Patterns with Guards

java
// Define the class Main
public class Main {
	static String classify(Object obj) {
		// Send switch (obj) { back to the caller
		return switch (obj) {
			case Integer i when i > 100 -> "Big integer";
			case Integer i -> "Small integer";
			default -> "Not an integer";
		};
	}
	// Program entry point: the JVM starts running here
	public static void main(String[] args) {
		// Print a line to the console
		System.out.println(classify(500));
	}
}

Record Patterns

Record patterns let you deconstruct a record object directly as part of a type check, immediately exposing its individual component fields as local variables. This avoids the extra step of matching the record's type and then separately calling its accessor methods.

Example: Record Patterns

java
public class Main {
	record Point(int x, int y) {}
	public static void main(String[] args) {
		Object obj = new Point(3, 4);
		if (obj instanceof Point(int x, int y)) { // deconstructed directly
			System.out.println(x + "," + y);
		}
	}
}
Related Topics
{# common_mistakes/chapter_summary/browser_support: on Hindi pages the view already swaps in the hi_ translation fields (or blanks these out if untranslated), so this renders correctly for both languages without a lang_code check here. #}
Common Mistakes
  1. Using the pattern variable outside the branch where the match is known to succeed, such as after if (!(obj instanceof String s)), which gives a 'cannot find symbol' error.
  2. Putting a general case like case Object o before a specific one like case String s, which is a compile error because the later case is dominated.
  3. Passing null to a pattern switch without a case null, which throws a NullPointerException.

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.