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

Java Pattern Matching

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
public class Main {
	static String describe(Object obj) {
		return switch (obj) {
			case Integer i -> "Integer: " + i;
			case String s -> "String: " + s;
			default -> "Unknown";
		};
	}
	public static void main(String[] args) {
		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
public class Main {
	static String classify(Object obj) {
		return switch (obj) {
			case Integer i when i > 100 -> "Big integer";
			case Integer i -> "Small integer";
			default -> "Not an integer";
		};
	}
	public static void main(String[] args) {
		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);
		}
	}
}

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.