Unlocking The Power of Pattern Matching
Pattern Matching in Java
Haim Michael https://lifemichael.com
What is Pattern Matching?
• Pattern matching simplifies conditional logic by allowing developers to
test and extract data from objects more concisely. Using Pattern
Matching we can eliminate boilerplate code (especially when using
instanceof checks and switch expressions).
The instanceof Operator
public class InstanceOfDemo {
public static void main(String[] args) {
var ob = new Dog();
//the old way
if(ob instanceof Dog) {
((Dog)ob).hau();
}
//the new way
if(ob instanceof Dog dog) {
dog.hau();
}
}
}
The dog variable is a pattern variable
assigned with the value of ob if instanceof
returns true.
com.lifemichael.meetups.java.patternmatching.InstanceOfDemo
The switch Expression
public class SwitchPatternMatching {
public static void main(String[] args) {
var ob = new Dog();
hello(ob);
}
public static void hello(Object object) {
switch(object) {
case Dog dog -> dog.hau();
case Tiger tiger -> tiger.miaurrr();
case Cat cat -> cat.miau();
case null, default -> System.out.println("not supported");
}
}
}
Make sure you know the difference between
Switch Expression and Switch Statement.
com.lifemichael.meetups.java.patternmatching.SwitchPatternMatching
com.lifemichael.meetups.java.patternmatching.SwitchExpressionDemo
The Completeness Requirement
• When using pattern matching together with Switch Statement (or Switch
Expressions), all possible values must be handled. Usually, we will
achieve that using the default case, and using a sealed class.
The Completeness Requirement
public class SealedProgram {
public static void main(String[] args) {
var ob = new Dog();
hello(ob);
}
public static void hello(Animal ob) {
switch(ob) {
case Dog dog -> dog.hau();
case Tiger tiger -> tiger.miaurrr();
case Cat cat -> cat.miau();
case Human human -> human.hello();
}
}
}
com.lifemichael.meetups.java.patternmatching.sealed.demo.SealedProgram
Guarded Patterns
public class GuardedProgram {
public static void main(String[] args) {
test(new Rectangle(3,5));
}
public static void test(Shape o) {
switch(o) {
case Rectangle rec when rec.area()>20 -> System.out.println("big rectangle");
case Rectangle rec when rec.area()<=20 -> System.out.println("small rectangle");
case Circle circle -> System.out.println("nice circle");
case Shape shape -> System.out.println("it is impossible to calculate area");
}
}
}
The when keyword works when comparing
objects only.
com.lifemichael.meetups.java.patternmatching.guarded
Record Deconstruction Patterns
• We can easily use Pattern Matching with classes that were defined as
record classes in order to extract values from the object we compare.
Record Deconstruction Patterns
record Rectangle (double width, double height) {}
public class Program {
public static void main(String[] args) {
Rectangle rec = new Rectangle(3,4);
describe(rec);
}
public static void describe(Object ob) {
if(ob instanceof Rectangle(double w, double h)) {
System.out.println("width="+w);
System.out.println("height="+h);
System.out.println("area="+(w*h));
System.out.println("perimeter="+(2*(w+h)));
}
}
}
com.lifemichael.meetups.java.patternmatching.simplerecord
Composable Patterns Deconstruction
• We can compose new patterns from patterns that already exist.
Composable Patterns Deconstruction
interface Line {}
record Point(double x, double y) {}
enum Color {BLUE, YELLOW, RED, GREEN}
interface Rectangle {}
record ColourLine(Point p1, Point p2, Color color) {}
record ColourRectangle(Point topLeft, Point bottomRight, Color color) implements Rectangle {}
com.lifemichael.meetups.java.patternmatching.composable.SimpleDemo
Composable Patterns Deconstruction
public class SimpleDemo {
public static void main(String[] args) {
var ob = new ColourRectangle(new Point(3,4),new Point(10,2),Color.BLUE);
printDetails(ob);
}
public static void printDetails(Rectangle rec) {
if(rec instanceof ColourRectangle(Point topLeft, Point bottomRight, Color color)) {
System.out.println("color="+color);
System.out.println("top left="+topLeft);
System.out.println("bottom right="+bottomRight);
}
}
}
com.lifemichael.meetups.java.patternmatching.composable.SimpleDemo
Unnamed Variables and Patterns
• We can improve the readability of our code by using the _ character when
dealing with pattern variables we don’t use.
Unnamed Variables and Patterns
interface Line {}
record Point(double x, double y) {}
enum Color {BLUE, YELLOW, RED, GREEN}
interface Rectangle {}
record ColourLine(Point p1, Point p2, Color color) {}
record ColourRectangle(Point topLeft, Point bottomRight, Color color) implements Rectangle {}
com.lifemichael.meetups.java.patternmatching.composable.unnamed
Unnamed Variables and Patterns
public class SimpleDemo {
public static void main(String[] args) {
var ob = new ColourRectangle(new Point(3,4),new Point(10,2),Color.BLUE);
printDetails(ob);
}
public static void printDetails(Rectangle rec) {
if(rec instanceof ColourRectangle(Point topLeft, Point bottomRight, _)) {
System.out.println("top left="+topLeft);
System.out.println("bottom right="+bottomRight);
}
}
}
com.lifemichael.meetups.java.patternmatching.composable.unnamed
Unnamed Variables and Patterns
• There are various cases in which we can use the unnamed pattern
variable.
Unnamed Variables and Patterns
com.lifemichael.meetups.java.patternmatching.composable.unnamed.switchdemo
public class SimpleDemo {
public static void main(String[] args) {
var data = 12;
testType(data);
}
public static void testType(Object data) {
switch(data) {
case String _ -> System.out.println("String");
case Integer _ -> System.out.println("Integer");
case Double _ -> System.out.println("Double");
default -> System.out.println("Un Known");
}
}
}
Questions & Answers
• Thanks for attending my talk.
haim.michael@lifemichael.com
+972 54 6655837
https://blog.lifemichael.com

Introduction to Pattern Matching in Java [Free Meetup]

  • 1.
    Unlocking The Powerof Pattern Matching Pattern Matching in Java Haim Michael https://lifemichael.com
  • 2.
    What is PatternMatching? • Pattern matching simplifies conditional logic by allowing developers to test and extract data from objects more concisely. Using Pattern Matching we can eliminate boilerplate code (especially when using instanceof checks and switch expressions).
  • 3.
    The instanceof Operator publicclass InstanceOfDemo { public static void main(String[] args) { var ob = new Dog(); //the old way if(ob instanceof Dog) { ((Dog)ob).hau(); } //the new way if(ob instanceof Dog dog) { dog.hau(); } } } The dog variable is a pattern variable assigned with the value of ob if instanceof returns true. com.lifemichael.meetups.java.patternmatching.InstanceOfDemo
  • 4.
    The switch Expression publicclass SwitchPatternMatching { public static void main(String[] args) { var ob = new Dog(); hello(ob); } public static void hello(Object object) { switch(object) { case Dog dog -> dog.hau(); case Tiger tiger -> tiger.miaurrr(); case Cat cat -> cat.miau(); case null, default -> System.out.println("not supported"); } } } Make sure you know the difference between Switch Expression and Switch Statement. com.lifemichael.meetups.java.patternmatching.SwitchPatternMatching com.lifemichael.meetups.java.patternmatching.SwitchExpressionDemo
  • 5.
    The Completeness Requirement •When using pattern matching together with Switch Statement (or Switch Expressions), all possible values must be handled. Usually, we will achieve that using the default case, and using a sealed class.
  • 6.
    The Completeness Requirement publicclass SealedProgram { public static void main(String[] args) { var ob = new Dog(); hello(ob); } public static void hello(Animal ob) { switch(ob) { case Dog dog -> dog.hau(); case Tiger tiger -> tiger.miaurrr(); case Cat cat -> cat.miau(); case Human human -> human.hello(); } } } com.lifemichael.meetups.java.patternmatching.sealed.demo.SealedProgram
  • 7.
    Guarded Patterns public classGuardedProgram { public static void main(String[] args) { test(new Rectangle(3,5)); } public static void test(Shape o) { switch(o) { case Rectangle rec when rec.area()>20 -> System.out.println("big rectangle"); case Rectangle rec when rec.area()<=20 -> System.out.println("small rectangle"); case Circle circle -> System.out.println("nice circle"); case Shape shape -> System.out.println("it is impossible to calculate area"); } } } The when keyword works when comparing objects only. com.lifemichael.meetups.java.patternmatching.guarded
  • 8.
    Record Deconstruction Patterns •We can easily use Pattern Matching with classes that were defined as record classes in order to extract values from the object we compare.
  • 9.
    Record Deconstruction Patterns recordRectangle (double width, double height) {} public class Program { public static void main(String[] args) { Rectangle rec = new Rectangle(3,4); describe(rec); } public static void describe(Object ob) { if(ob instanceof Rectangle(double w, double h)) { System.out.println("width="+w); System.out.println("height="+h); System.out.println("area="+(w*h)); System.out.println("perimeter="+(2*(w+h))); } } } com.lifemichael.meetups.java.patternmatching.simplerecord
  • 10.
    Composable Patterns Deconstruction •We can compose new patterns from patterns that already exist.
  • 11.
    Composable Patterns Deconstruction interfaceLine {} record Point(double x, double y) {} enum Color {BLUE, YELLOW, RED, GREEN} interface Rectangle {} record ColourLine(Point p1, Point p2, Color color) {} record ColourRectangle(Point topLeft, Point bottomRight, Color color) implements Rectangle {} com.lifemichael.meetups.java.patternmatching.composable.SimpleDemo
  • 12.
    Composable Patterns Deconstruction publicclass SimpleDemo { public static void main(String[] args) { var ob = new ColourRectangle(new Point(3,4),new Point(10,2),Color.BLUE); printDetails(ob); } public static void printDetails(Rectangle rec) { if(rec instanceof ColourRectangle(Point topLeft, Point bottomRight, Color color)) { System.out.println("color="+color); System.out.println("top left="+topLeft); System.out.println("bottom right="+bottomRight); } } } com.lifemichael.meetups.java.patternmatching.composable.SimpleDemo
  • 13.
    Unnamed Variables andPatterns • We can improve the readability of our code by using the _ character when dealing with pattern variables we don’t use.
  • 14.
    Unnamed Variables andPatterns interface Line {} record Point(double x, double y) {} enum Color {BLUE, YELLOW, RED, GREEN} interface Rectangle {} record ColourLine(Point p1, Point p2, Color color) {} record ColourRectangle(Point topLeft, Point bottomRight, Color color) implements Rectangle {} com.lifemichael.meetups.java.patternmatching.composable.unnamed
  • 15.
    Unnamed Variables andPatterns public class SimpleDemo { public static void main(String[] args) { var ob = new ColourRectangle(new Point(3,4),new Point(10,2),Color.BLUE); printDetails(ob); } public static void printDetails(Rectangle rec) { if(rec instanceof ColourRectangle(Point topLeft, Point bottomRight, _)) { System.out.println("top left="+topLeft); System.out.println("bottom right="+bottomRight); } } } com.lifemichael.meetups.java.patternmatching.composable.unnamed
  • 16.
    Unnamed Variables andPatterns • There are various cases in which we can use the unnamed pattern variable.
  • 17.
    Unnamed Variables andPatterns com.lifemichael.meetups.java.patternmatching.composable.unnamed.switchdemo public class SimpleDemo { public static void main(String[] args) { var data = 12; testType(data); } public static void testType(Object data) { switch(data) { case String _ -> System.out.println("String"); case Integer _ -> System.out.println("Integer"); case Double _ -> System.out.println("Double"); default -> System.out.println("Un Known"); } } }
  • 18.
    Questions & Answers •Thanks for attending my talk. [email protected] +972 54 6655837 https://blog.lifemichael.com