Working with Pattern Matching
1. Using Pattern Matching for instanceof
Example: Auto-cast pattern
if (obj instanceof String s && !s.isEmpty()) {
System.out.println(s.toUpperCase());
}
| Aspect | Detail |
|---|---|
| Variable scope | True branch + remainder of && expression |
| Negation | !(obj instanceof String s) — s usable AFTER if |
2. Understanding Type Patterns
| Pattern | Form |
|---|---|
| Type | Type identifier |
| Var | var x (matches anything) |
| Constant | Literal in switch case |
| Null | case null |
3. Using Pattern Matching in switch
Example: Switch with patterns
String format(Object o) {
return switch (o) {
case Integer i -> "int " + i;
case Long l -> "long " + l;
case String s -> "string \"" + s + "\"";
case null -> "null";
default -> o.toString();
};
}
| Rule | Detail |
|---|---|
| Selector type | Any reference type |
| Dominance | More specific patterns must come first |
| Null handling | Explicit case null required (else NPE) |
4. Using Guarded Patterns
Example: when clause
switch (shape) {
case Triangle t when t.equilateral() -> "equilateral";
case Triangle t -> "general triangle";
default -> "other";
}
| Element | Detail |
|---|---|
when clause | Boolean guard added to pattern |
| Order matters | Guarded version before plain |
5. Understanding Record Patterns JAVA 21+
Example: Record pattern
record Point(int x, int y) {}
if (obj instanceof Point(int x, int y)) {
System.out.println(x + ", " + y);
}
| Form | Result |
|---|---|
Point(int x, int y) | Bind components by name |
Point(var x, var y) | Use type inference |
6. Deconstructing Records with Patterns
| Mechanism | Detail |
|---|---|
| Auto-extract | Components bound to local vars |
| Type check | Combined with instanceof or switch |
| No accessors needed | Direct component access |
7. Using Nested Record Patterns
Example: Nested deconstruction
record Line(Point start, Point end) {}
if (line instanceof Line(Point(var x1, var y1), Point(var x2, var y2))) {
double dist = Math.hypot(x2 - x1, y2 - y1);
}
| Capability | Detail |
|---|---|
| Arbitrary nesting | Deconstruct nested record components |
Mix with var | Reduces verbosity |
8. Understanding Pattern Matching Exhaustiveness
| Selector | Exhaustive Requirement |
|---|---|
| Sealed type | All permitted subtypes covered |
| Enum | All constants covered |
| Record patterns | All component combinations covered |
| Other | default required |
9. Combining Patterns with Sealed Classes
| Benefit | Detail |
|---|---|
| Type-safe enums | Replace tagged unions |
| Compile-time checks | Adding subtype reveals all switches needing update |
| Cleaner ADTs | Algebraic data types in idiomatic Java |
10. Using Unnamed Patterns JAVA 21 PREVIEW
Example: Underscore for unused
// Preview: unnamed pattern variable
if (obj instanceof Point(int x, _)) { ... }
switch (r) {
case Success(_) -> handleOk();
case Failure(var err) -> log(err);
}
| Symbol | Use |
|---|---|
_ | Discard component (unused binding) |
| Status | Preview as of Java 21; standardized in later releases |