Java 23 Pattern Matching: Rewriting Legacy Code with Modern Syntax
Java's pattern matching has evolved from a simple instanceof check to a complete algebraic data type system. Java 23 brings unnamed patterns and primitive patterns that complete the picture.
From instanceof Chains to Sealed Hierarchies
// Before: fragile instanceof chains
if (shape instanceof Circle c) {
return Math.PI * c.radius() * c.radius();
} else if (shape instanceof Rectangle r) {
return r.width() * r.height();
}
// After: exhaustive switch 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 {}
double area(Shape shape) {
return switch (shape) {
case Circle(var r) -> Math.PI * r * r;
case Rectangle(var w, var h) -> w * h;
case Triangle(var b, var h) -> 0.5 * b * h;
};
}
Nested Record Patterns
Deconstruct deeply nested structures in a single pattern:
record Address(String city, String country) {}
record Customer(String name, Address address) {}
String greeting(Customer c) {
return switch (c) {
case Customer(var n, Address(_, "India")) -> "Namaste, " + n;
case Customer(var n, Address(_, "Japan")) -> "Konnichiwa, " + n;
case Customer(var n, _) -> "Hello, " + n;
};
}
Pattern matching makes Java code more concise, type-safe, and expressive — three things Java was rarely accused of being.