This is a teaser article. Pattern matching represents Java's first serious steps toward a programming paradigm that functional languages have enjoyed for decades. Combined with switch expressions, these features fundamentally transform how you write conditional logic and type checks. This article explores pattern matching for instanceof, switch expressions, guarded patterns, record destructuring, and how sealed types guarantee exhaustiveness.
Why This Matters
For decades, Java developers have suffered through the "instanceof-cast ceremony":
// The old pain point - Java 8
if (obj instanceof String) {
String s = (String) obj;
return "String: " + s.length();
} else if (obj instanceof Integer) {
Integer i = (Integer) obj;
return "Integer: " + i;
}
Pattern matching collapses this:
// Java 16+ - Pattern matching
if (obj instanceof String s) {
return "String: " + s.length();
} else if (obj instanceof Integer i) {
return "Integer: " + i;
}
Java 17 brings these together: pattern matching + switch expressions create powerful, type-safe conditional logic.
What is Pattern Matching?
Pattern matching is structural decomposition combined with conditional dispatch. You're asking:
- "What shape is this data?"
- "If it matches, bind the components to names I can use"
Type Patterns (Java 16+)
if (obj instanceof String s) {
System.out.println(s.length());
}
Guarded Patterns (Java 16+)
if (obj instanceof String s && s.length() > 5) {
return s.toUpperCase();
}
Pattern Matching in Switch (Java 17+)
String result = switch (obj) {
case String s -> "String: " + s;
case Integer i -> "Integer: " + i;
case null -> "Null";
default -> "Unknown";
};
Real-World Example 1: equals() Implementation
Before Java 16:
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
Point other = (Point) obj;
return this.x == other.x && this.y == other.y;
}
Java 16+ with pattern matching:
@Override
public boolean equals(Object obj) {
return obj instanceof Point p &&
this.x == p.x && this.y == p.y;
}
Real-World Example 2: Switch Expressions
Before Java 14:
String dayType;
switch (day) {
case MONDAY: case TUESDAY: case WEDNESDAY:
case THURSDAY: case FRIDAY:
dayType = "Weekday";
break;
case SATURDAY: case SUNDAY:
dayType = "Weekend";
break;
}
Java 14+ with arrow syntax:
String dayType = switch (day) {
case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> "Weekday";
case SATURDAY, SUNDAY -> "Weekend";
};
Real-World Example 3: Pattern Matching with Sealed Types
sealed interface Shape permits Circle, Rectangle, Triangle {}
record Circle(double radius) implements Shape {}
record Rectangle(double width, double height) implements Shape {}
record Triangle(double base, double height) implements Shape {}
int area = switch (shape) {
case Circle c -> (int) (Math.PI * c.radius() * c.radius());
case Rectangle r -> r.width() * r.height();
case Triangle t -> (t.base() * t.height()) / 2;
};
Real-World Example 4: Guarded Patterns
String classify = switch (obj) {
case String s when s.isEmpty() -> "Empty string";
case String s when s.length() < 5 -> "Short string: " + s;
case String s -> "Long string: " + s;
default -> "Not a string";
};
Real-World Example 5: Result Pattern
sealed interface Result<T> permits Success, Failure {}
record Success<T>(T value) implements Result<T> {}
record Failure<T>(String error) implements Result<T> {}
public static <T> String describe(Result<T> result) {
return switch (result) {
case Success<T> s -> "Success: " + s.value();
case Failure<T> f -> "Failure: " + f.error();
};
}
Key Insight
Pattern matching represents a paradigm shift toward declarative conditional logic. Combined with sealed types, the compiler enforces exhaustiveness at compile-time, preventing entire classes of runtime type errors.
Read the Full Article
Discover more about pattern matching and switch expressions:
- Type patterns and scope rules
- Switch expressions vs traditional switch
- Guarded patterns with when clause
- Record destructuring in patterns
- Sealed types with exhaustiveness checking
- Best practices and migration strategy
Full article: https://blog.9mac.dev/java-17-features-every-senior-developer-should-know-part-4-pattern-matching-and-switch-expressions
Clone and Run
git clone https://github.com/dawid-swist/blog-9mac-dev-code.git
cd blog-post-examples/java/2025-10-25-java17-features-every-senior-developer-should-know
../../gradlew test --tests *part4*
Part of the "Java 17 Features Every Senior Developer Should Know" series
- Part 1: var Keyword
- Part 2: Records
- Part 3: Sealed Classes
- Part 4: Pattern Matching & Switch (You are here)
- Part 5: Text Blocks
- Part 6: Syntax Cheat Sheet
Top comments (0)