Add patterns module: pattern matching from JDK 21 to 27
Type, record and primitive patterns, guards, sealed exhaustiveness, MatchException via separate compilation, and eight captured transcripts. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01TF9JWFvJSNm6HVzswzZU5a
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
public class Guards {
|
||||
static String size(Object o) {
|
||||
return switch (o) {
|
||||
case String s when s.isEmpty() -> "empty string";
|
||||
case String s when s.length() < 5 -> "short string: " + s;
|
||||
case String s -> "long string: " + s;
|
||||
case Integer i when i < 0 -> "negative " + i;
|
||||
case Integer i -> "int " + i;
|
||||
default -> "other";
|
||||
};
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
for (Object o : new Object[]{"", "abc", "abcdefgh", -4, 12, 1.5}) System.out.println(size(o));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
public class MatchExceptionDemo {
|
||||
record Fragile(int v) {
|
||||
public int v() { throw new IllegalStateException("accessor blew up"); }
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
Object o = new Fragile(1);
|
||||
try {
|
||||
if (o instanceof Fragile(int v)) System.out.println("matched " + v);
|
||||
} catch (MatchException e) {
|
||||
System.out.println("MatchException: " + e.getMessage());
|
||||
System.out.println("cause: " + e.getCause());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
public class NullCase {
|
||||
static String withoutCaseNull(Object o) {
|
||||
return switch (o) {
|
||||
case String s -> "string";
|
||||
default -> "other";
|
||||
};
|
||||
}
|
||||
|
||||
static String withCaseNull(Object o) {
|
||||
return switch (o) {
|
||||
case null -> "null!";
|
||||
case String s -> "string";
|
||||
default -> "other";
|
||||
};
|
||||
}
|
||||
|
||||
static String combined(Object o) {
|
||||
return switch (o) {
|
||||
case String s -> "string";
|
||||
case null, default -> "null or something else";
|
||||
};
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
try { System.out.println(withoutCaseNull(null)); }
|
||||
catch (NullPointerException e) { System.out.println("without case null: NullPointerException"); }
|
||||
System.out.println("with case null: " + withCaseNull(null));
|
||||
System.out.println("case null, default: " + combined(null));
|
||||
System.out.println("instanceof with null: " + (null instanceof String));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
public class RecordPatterns {
|
||||
record Point(int x, int y) {}
|
||||
record Line(Point from, Point to) {}
|
||||
record Box<T>(T content) {}
|
||||
|
||||
// Deconstruct a record: the components are bound to x and y.
|
||||
static String where(Object o) {
|
||||
if (o instanceof Point(int x, int y)) {
|
||||
return "point at " + x + "," + y;
|
||||
}
|
||||
return "not a point";
|
||||
}
|
||||
|
||||
// Patterns nest: take a Line apart into its four coordinates in one step.
|
||||
static int length1(Line line) {
|
||||
if (line instanceof Line(Point(var x1, var y1), Point(var x2, var y2))) {
|
||||
return Math.abs(x2 - x1) + Math.abs(y2 - y1);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// A nested pattern can also test the component's type.
|
||||
static String box(Box<Object> b) {
|
||||
return switch (b) {
|
||||
case Box<Object>(String s) -> "box of string " + s;
|
||||
case Box<Object>(Integer i) -> "box of int " + i;
|
||||
case Box<Object>(var other) -> "box of " + other;
|
||||
};
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(where(new Point(3, 4)));
|
||||
System.out.println(where("nope"));
|
||||
System.out.println(length1(new Line(new Point(0, 0), new Point(3, 4))));
|
||||
System.out.println(box(new Box<>("hi")));
|
||||
System.out.println(box(new Box<>(7)));
|
||||
System.out.println(box(new Box<>(2.5)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
public class SealedExhaustive {
|
||||
sealed interface Shape permits Circle, Square, Rect {}
|
||||
record Circle(double r) implements Shape {}
|
||||
record Square(double side) implements Shape {}
|
||||
record Rect(double w, double h) implements Shape {}
|
||||
|
||||
// No default: the compiler checks that every permitted subtype is covered.
|
||||
static double area(Shape s) {
|
||||
return switch (s) {
|
||||
case Circle(double r) -> Math.PI * r * r;
|
||||
case Square(double side) -> side * side;
|
||||
case Rect(double w, double h) -> w * h;
|
||||
};
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
for (Shape s : new Shape[]{new Circle(1), new Square(2), new Rect(2, 3)}) {
|
||||
System.out.printf("%s -> %.2f%n", s, area(s));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
public class TypePatterns {
|
||||
// The old way: test, cast, then use.
|
||||
static String oldStyle(Object o) {
|
||||
if (o instanceof String) {
|
||||
String s = (String) o;
|
||||
return "string of length " + s.length();
|
||||
}
|
||||
return "something else";
|
||||
}
|
||||
|
||||
// The pattern way: test and bind in one step.
|
||||
static String newStyle(Object o) {
|
||||
if (o instanceof String s) {
|
||||
return "string of length " + s.length();
|
||||
}
|
||||
return "something else";
|
||||
}
|
||||
|
||||
// The binding variable stays in scope wherever the test is known to have succeeded.
|
||||
static int lengthOrMinusOne(Object o) {
|
||||
if (!(o instanceof String s)) {
|
||||
return -1;
|
||||
}
|
||||
return s.length(); // s is in scope here: we only get here if the test succeeded
|
||||
}
|
||||
|
||||
// A switch can test many types in a row.
|
||||
static String describe(Object o) {
|
||||
return switch (o) {
|
||||
case Integer i -> "int " + (i + 1);
|
||||
case String s -> "string " + s.toUpperCase();
|
||||
case int[] arr -> "int array of " + arr.length;
|
||||
default -> "other " + o.getClass().getSimpleName();
|
||||
};
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(oldStyle("hello") + " / " + newStyle("hello"));
|
||||
System.out.println(lengthOrMinusOne("abc") + " " + lengthOrMinusOne(42));
|
||||
System.out.println(describe(41));
|
||||
System.out.println(describe("java"));
|
||||
System.out.println(describe(new int[]{1, 2, 3}));
|
||||
System.out.println(describe(3.5));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
public class Unnamed {
|
||||
record Point(int x, int y) {}
|
||||
sealed interface Shape permits Circle, Square {}
|
||||
record Circle(double r) implements Shape {}
|
||||
record Square(double side) implements Shape {}
|
||||
|
||||
static String kind(Shape s) {
|
||||
return switch (s) {
|
||||
case Circle _ -> "round"; // the type matters, the value does not
|
||||
case Square _ -> "angular";
|
||||
};
|
||||
}
|
||||
|
||||
static int xOnly(Object o) {
|
||||
if (o instanceof Point(int x, _)) return x; // do not care about y
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(kind(new Circle(1)) + " " + kind(new Square(1)));
|
||||
System.out.println(xOnly(new Point(5, 9)));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user