Slide 1

Slide 1 text

State of Pattern Matching in Java Deepu K Sasidharan @deepu105 | deepu.tech

Slide 2

Slide 2 text

Deepu K Sasidharan JHipster co-lead Creator of KDash Developer Advocate at Okta OSS aficionado, author, speaker, polyglot dev @deepu105 deepu.tech deepu105

Slide 3

Slide 3 text

Pattern matching? “The act of checking a given sequence of tokens for the presence of the constituents of some pattern”

Slide 4

Slide 4 text

Pattern matching? Sequence patterns = Regular expressions Tree patterns = Pattern matching data structures

Slide 5

Slide 5 text

Why Pattern matching? ● Reduced cognitive complexity ○ Much more concise code and better readability ○ More complex logic can be expressed with less lines of code ○ Simpler to write and maintain ● Reduced reliance on reflection and casting ● Avoid pattern dominance ● Pattern exhaustiveness which avoids bugs

Slide 6

Slide 6 text

Pattern matching features ● Enum matching in switch statements ● Match type/value in switch statements ● Match type/value in if statements ● Pattern matched variable assignments ● Null checks ● Type guards ● Refined patterns ● Pattern dominance and type exhaustion ● Partial/Nested/Compound type and/or value checks ● Shallow/Deep Position-based Destructured matching

Slide 7

Slide 7 text

Pattern matching in the wild Most modern languages support some level of pattern matching for data structures These are some languages with good support for it ● Rust ● OCaml ● Haskell ● C# ● F# ● Scala ● Python ● Ruby

Slide 8

Slide 8 text

Pattern matching in the wild: Rust fn main() { let p = Point { x: 0, y: 7 }; match p { Point { x, y: 0 } => println!("On the x axis at {}", x), Point { x: 0, y } => println!("On the y axis at {}", y), Point { x, y } => println!("On neither axis: ({}, {})", x, y), } }

Slide 9

Slide 9 text

Pattern matching in the wild: Scala def showNotification(notification: Notification): String = { notification match { case Email(sender, title, _) => s"You got an email from $sender with title: $title" case SMS(number, message) => s"You got an SMS from $number! Message: $message" case VoiceRecording(name, link) => s"You received a Voice Recording from $name! Click the link to hear it: $link" } }

Slide 10

Slide 10 text

Pattern matching in the wild: C# public decimal CalculateDiscount(Order order) => order switch { (Items: > 10, Cost: > 1000.00m) => 0.10m, (Items: > 5, Cost: > 500.00m) => 0.05m, Order { Cost: > 250.00m } => 0.02m, null => throw new Exception(nameof(order), "Can't calculate discount on null order"), var someObject => 0m, };

Slide 11

Slide 11 text

Pattern matching in Java

Slide 12

Slide 12 text

Pattern matching in Java Java is quite behind the curve when it comes to pattern matching. With Java 17 we have most of the building blocks ● Switch statements ● Switch expressions (Java 14) ● Pattern matching for instanceof (Java 16) ● Sealed classes (Java 17) ● Pattern matching for switch (Java 17 preview - JEP 406)

Slide 13

Slide 13 text

Match type in if statements // Before if (obj instanceof String) { String s = (String) obj; System.out.println(s.length()); } // After if (obj instanceof String s) { // Let pattern matching do the work! System.out.println(s.length()); }

Slide 14

Slide 14 text

Match type guard for returns // Before public boolean equals(Object o) { if (!(o instanceof Point)) return false; Point other = (Point) o; return x == other.x && y == other.y; } // After public boolean equals(Object o) { return (o instanceof Point other) && x == other.x && y == other.y; }

Slide 15

Slide 15 text

Match type guard for returns // Before var x = o instanceof Point ? ((Point)o).x : 0; System.out.println(x); // After var x = o instanceof Point p ? p.x : 0; System.out.println(x);

Slide 16

Slide 16 text

Match type in if statements static String formatter(Object o) { String formatted = "unknown"; if (o instanceof Integer i) { formatted = String.format("int %d", i); } else if (o instanceof Long l) { formatted = String.format("long %d", l); } else if (o instanceof Double d) { formatted = String.format("double %f", d); } else if (o instanceof String s) { formatted = String.format("String %s", s); } return formatted; }

Slide 17

Slide 17 text

Match type in switch cases (preview) static String formatter(Object o) { return switch (o) { case Integer i -> String.format("int %d", i); case Long l -> String.format("long %d", l); case Double d -> String.format("double %f", d); case String s -> String.format("String %s", s); default -> o.toString(); }; }

Slide 18

Slide 18 text

Null checks with switch (preview) static String formatter(Object o) { return switch (o) { case null -> "Oops"; ... case String s -> String.format("String %s", s); default -> o.toString(); }; } or static String formatter(Object o) { return switch (o) { ... case String s -> String.format("String %s", s); case null, default -> "Oops"; }; }

Slide 19

Slide 19 text

Type Guards & pattern refinement (preview) static void test(Object o) { if ((o instanceof String s) && s.length() > 3) { System.out.println(s); } else { System.out.println("Not a string "); } } Or static void test(Object o) { switch (o) { case String s && (s.length() > 3) -> System.out.println(s); case String s -> System.out.println("Invalid string "); default -> System.out.println("Not a string "); } }

Slide 20

Slide 20 text

Sealed classes public abstract sealed class Shape permits Circle, Rectangle, Square { ... } Or public abstract sealed class Shape { final class Circle extends Shape { ... } final class Square extends Shape { ... } final class Rectangle extends Shape { ... } } A Sealed class/interface lets you control which class/interface can extend/implement them

Slide 21

Slide 21 text

Sealed classes Constraints imposed on subclasses 1. Sealed class and its permitted subclasses must be in same module (same package in case of an unnamed module) 2. Every permitted subclass must directly extend the sealed class 3. Every permitted subclass must use a modifier to describe propagation of sealing (final, sealed, or non-sealed)

Slide 22

Slide 22 text

Sealed classes public sealed interface Shape permits Circle, Rectangle, Square, WeirdShape { ... } public record Circle(int r) implements Shape { ... } public final class Square implements Shape { ... } public sealed class Rectangle implements Shape permits TransparentRectangle, FilledRectangle { ... } public non-sealed class WeirdShape implements Shape { ... }

Slide 23

Slide 23 text

How is sealed classes related to pattern matching?

Slide 24

Slide 24 text

Sealed classes & pattern matching Shape rotate(Shape shape, double angle) { return switch (shape) { // this will be 'switch' expression does not cover all possible input values error case Circle c -> c; case Square s -> shape.rotate(angle); }; } Shape rotate(Shape shape, double angle) { return switch (shape) { case Circle c -> c; case Rectangle r -> shape.rotate(angle); case Square s -> shape.rotate(angle); case WeirdShape w -> shape.rotate(angle); // still exhaustive // no default needed! }; } Sealed classes will allow compiler to enforce exhaustive pattern matching

Slide 25

Slide 25 text

Pattern matching features in Java ● Enum matching in switch statements ✅ ● Match type/value in switch statements ✅ ● Match type/value in if statements ✅ ● Pattern matched variable assignments ✅ ● Null checks ✅ ● Type guards ✅ ● Refined patterns 🆗 ● Pattern dominance and type exhaustion 🆗 ● Partial/Nested/Compound type and/or value checks ❌ ● Shallow/Deep Position-based Destructured matching ❌

Slide 26

Slide 26 text

Future

Slide 27

Slide 27 text

Future ● Record Patterns & Array Patterns (Preview - JEP 405) - JDK 18 candidate ○ Destructure record patterns and values for instanceof operator ○ Destructure array patterns and values for instanceof operator ● Deconstruction for switch case patterns(maybe) ● Support for primitives in switch case pattern (maybe) ● Declare deconstruction patterns for classes (maybe)

Slide 28

Slide 28 text

Record patterns record Point(int x, int y) {} void printSum(Object o) { if (o instanceof Point(int x, int y)) { System.out.println(x+y); } } Deconstruct patterns for records.

Slide 29

Slide 29 text

Record patterns record Point(int x, int y) {} enum Color { RED, GREEN, BLUE } record ColoredPoint(Point p, Color c) {} void printSum(Object o) { if (o instanceof ColoredPoint(Point(int x, int y), Color c) { System.out.println(x+y); } } Deconstruct nested patterns for records

Slide 30

Slide 30 text

Array patterns static void printFirstTwoStrings(Object o) { if (o instanceof String[] { String s1, String s2, ... }){ System.out.println(s1 + s2); } } Deconstruct patterns for arrays.

Slide 31

Slide 31 text

Array + Record patterns static void printSumOfFirstTwoXCoords(Object o) { if (o instanceof Point[] { Point(var x1, var y1), Point(var x2, var y2), ... }) { System.out.println(x1 + x2); } } Deconstruct patterns for arrays of records.

Slide 32

Slide 32 text

Future of Pattern matching features in Java ● Enum matching in switch statements ✅ ● Match type/value in switch statements ✅ ● Match type/value in if statements ✅ ● Pattern matched variable assignments ✅ ● Null checks ✅ ● Type guards ✅ ● Refined patterns ✅ ● Pattern dominance and type exhaustion 🆗 ● Partial/Nested/Compound type and/or value checks 🆗 ● Shallow/Deep Position-based Destructured matching 🆗

Slide 33

Slide 33 text

Limitations of Pattern matching in Java ● JDK 17 preview ○ No deconstruction ○ No nested patterns ○ Type exhaustion is only for sealed classes and enums ○ Pattern refinement is limited ○ Still a preview feature ● JDK 18 preview (maybe) ○ No deconstruction for classes and in switch cases ○ No nested patterns for classes and in switch cases ○ Type exhaustion is only for sealed classes and enums ○ No feature for ignoring don’t-care patterns during deconstruction ○ No named patterns ○ Still a preview feature

Slide 34

Slide 34 text

Provide Feedback Pattern matching for switch: https://openjdk.java.net/jeps/406 Record Patterns & Array Patterns: https://openjdk.java.net/jeps/405 Discussions mailing list: [email protected]

Slide 35

Slide 35 text

Thank you Deepu K Sasidharan @deepu105 | deepu.tech