Optimizing AI for immediate response in Smart CCTV
The Art of Java Type Patterns
1. The Art of Java
Type Patterns
Simon Ritter, Deputy CTO | Azul
2. 2
Modern Java
• The six-month release cadence for Java has been really good
• Lots of new features added much faster than we've ever seen before
• Significant language changes are initially developed under project Amber
o "... explore and incubate smaller, productivity-oriented Java language features..."
o Most features go through at least two rounds of preview
• Many of the new features work both separately and combined with others
3. 3
Pattern Matching In Java
• java.util.regex
• This is not what we're here to talk about
Pattern p = Pattern.compile("a*b");
Matcher m = p.matcher("aaaaab");
boolean b = m.matches();
boolean b = Pattern.matches("a*b", "aaaaab");
4. 4
Pattern Matching Fundamentals
• A well used technique, been in use since the 1960s (used in Haskell, AWK, etc.)
match predicate pattern variables
Determines whether the pattern
matches a target
A pattern
Conditionally extracted if the
pattern matches the target
5. 5
Pattern Types
• Constant
o Match on a constant (already in use in a switch statement)
• Type
o Match on a type
• Deconstruction
o Match and extract
• var
o Uses type inference to map to a type pattern (effecively matches anything)
• Any (_)
o Matches anything but binds to nothing (an unused pattern variable). See JEP 302
7. 7
Switch Expressions
• Switch construct was a statement
o No concept of generating a result that could be assigned
• Rather clunky syntax
o Every case statement needs to be separated
o Must remember break (default is to fall through)
o Scope of local variables is not intuitive
8. 8
Switch Statement
int numberOfLetters;
switch (day) {
case MONDAY:
case FRIDAY:
case SUNDAY:
numberOfLetters = 6;
break;
case TUESDAY:
numberOfLetters = 7;
break;
case THURSDAY:
case SATURDAY:
numberOfLetters = 8;
break;
case WEDNESDAY:
numberOfLetters = 9;
break;
default:
throw new IllegalStateException("Huh?: " + day); };
9. 9
Switch Expression (JDK 12)
• Switch expressions must be complete (exhaustive)
o We'll come back to this later
int numberOfLetters = switch (day) {
case MONDAY, FRIDAY, SUNDAY -> 6;
case TUESDAY -> 7;
case THURSDAY, SATURDAY -> 8;
case WEDNESDAY -> 9;
default -> throw new IllegalStateException("Huh?: " + day);
};
11. 11
Simple Java Data Class
class Point {
private final double x;
private final double y;
public Point(double x, double y) {
this.x = x;
this.y = y;
}
public double x() {
return x;
}
public double y() {
return y;
}
}
12. 12
Records (JDK 14)
record Point(double x, double y) { }
record Anything<T>(T t) { } // Generic Record
public record Circle(double radius) {
private static final double PI = 3.142; // Static instance fields are allowed
public double area() {
return PI * radius * radius;
}
}
13. 13
Records Additional Details
• The base class of all records is java.lang.Record
o Records cannot sub-class (but may implement interfaces)
• Object methods equals(), hashCode() and toString() can be overridden
• Records are implicitly final (although you may add the modifier)
• Records do not follow the Java bean pattern
o x() not getX() in Point example
o record Point(getX, getY) // If you must
14. 14
Java Inheritance
• A class (or interface) in Java can be sub-classed by any class
o Unless it is marked as final
Shape
Triangle Square Pentagon
15. 15
Sealed Classes (JEP 360)
public sealed class Shape permits Triangle, Square, Pentagon { ... }
Shape
Triangle Square Pentagon Circle
X
16. 16
Sealed Classes (JEP 360)
• All sub-classes must have inheritance capabilities explicitly specified
// Restrict sub-classes to defined set
public sealed class Triangle permits Equilateral, Isosoles extends Shape { ... }
// Prevent any further sub-classing
public final class Square extends Shape { ... }
// Allow any classes to sub-class this one (open)
public non-sealed class Pentagon extends Shape { ... }
18. 18
Using The instanceof Operator
if (obj instanceof String) {
String s = (String)obj;
System.out.println(s.length());
}
We must always perform an
explicit cast with an assignment
19. 19
Pattern Matching For instanceof (JDK 14)
if (obj instanceof String s)
System.out.println(s.length());
else
// Use of s not allowed here
if (obj instanceof String s && s.length() > 0)
System.out.println(s.length());
// Compiler error
if (obj instanceof String s || s.length() > 0)
System.out.println(s.length());
20. 20
Pattern Matching For instanceof
public void doSomething(Object o) {
if (!(o instanceof String s))
return;
System.out.println(s.length()); // Scope of s valid
// Several hundred lines of code
System.out.println(s.length()); // Still in scope
}
21. 22
Flow Scoping For Binding Variables
• Scope of local variable runs from its declaration until the end of the block in which it is declared
o Locals are subject to definite assigment
• Binding variables are also subject to definite assignment
o The scope of a binding variable is the set of places in the program where it would be definitely assigned
o This is flow scoping
• However, scope is not the same as local variables
if (o instanceof Integer num) { ... }
else if (o instanceof Float num) { ... }
else if (o instanceof Long num) { ... }
Need flow scoping to be able
to reuse num as variable name
22. 23
Pattern Matching For instanceof Puzzler
• Will this work?
Object s = new Object();
if (s instanceof String s)
System.out.println("String of length " + s.length());
else
System.out.println("No string");
23. 25
Pattern Matching For switch
• Switch is limited on what types you can use (Integral values, Strings, enumerations)
• Expanded to allow type patterns to be matched
void typeTester(Object o) {
switch (o) {
case null -> System.out.println("Null type");
case String s -> System.out.println("String: " + s);
case Color c -> System.out.println("Color with RGB: " + c.getRGB());
case int[] ia -> System.out.println("Array of ints, length" + ia.length);
default -> System.out.println(o.toString());
}
}
24. 26
Pattern Matching For switch
• Null is special (and complicated)
• case null can be used in all switch statements and expressions
o If not included, it will be added by compiler at start (throwing NullPointerException)
void typeTester(Object o) {
switch (o) {
case String s -> System.out.println("String: " + s);
case Color c -> System.out.println("Color with RGB: " + c.getRGB());
case int[] ia -> System.out.println("Array of ints, length" + ia.length);
default -> System.out.println("Bad input!");
}
}
25. 27
Pattern Matching For switch
• Null is special (and complicated)
• case null can be used in all switch statements and expressions
o If not included, it will be added by compiler at start (throwing NullPointerException)
void typeTester(Object o) {
switch (o) {
case null -> throw new NullPointerException(); // Added by compiler
case String s -> System.out.println("String: " + s);
case Color c -> System.out.println("Color with RGB: " + c.getRGB());
case int[] ia -> System.out.println("Array of ints, length" + ia.length);
default -> System.out.println("Bad input!");
}
}
26. 28
Pattern Matching For switch
• Null is special (and complicated)
• case null can be used in all switch statements and expressions
o If not included, it will be added by compiler at start (throwing NullPointerException)
void typeTester(Object o) {
switch (o) {
case String s -> System.out.println("String: " + s);
case Color c -> System.out.println("Color with RGB: " + c.getRGB());
case int[] ia -> System.out.println("Array of ints, length" + ia.length);
null, default -> System.out.println("Bad input!"); // No NullPointerException
}
}
27. 29
Pattern Matching for switch (Completeness)
• Pattern switch statements (and all switch expressions) must be exhaustive
o All possible values must be handled
void typeTester(Object o) {
switch (o) {
case String s -> System.out.println("String: " + s);
case Integer i -> System.out.println("Integer with value " + i.getInteger());
}
}
void typeTester(Object o) {
switch (o) {
case String s -> System.out.println("String: " + s);
case Integer i -> System.out.println("Integer with value " + i.getInteger());
default -> System.out.println("Some other type");
}
}
28. 30
Pattern Matching for switch (Completeness)
void typeTester(Shape shape) { // Using previous sealed class example
switch (shape) {
case Triangle t -> System.out.println("It's a triangle");
case Square s -> System.out.println("It's a square");
case Pentagon p -> System.out.println("It's a pentagon");
case Shape s -> System.out.println("It's a shape");
}
}
29. 31
Guarded Patterns
void shapeTester(Shape shape) { // Using previous sealed class example
switch (shape) {
case Triangle t && t.area() > 25 -> System.out.println("It's a big triangle");
case Triangle t -> System.out.println("It's a small triangle");
case Square s -> System.out.println("It's a square");
case Pentagon p -> System.out.println("It's a pentagon");
case Shape s -> System.out.println("It's a shape");
}
}
GuardedPattern:
PrimaryPattern && ConditionalAndExpression
30. 32
Pattern Dominance
• Less specific cases must not hide more specific cases
void typeTester(Shape shape) {
switch (shape) {
case Shape s -> System.out.println("It's a shape");
case Triangle t -> System.out.println("It's a triangle");
case Square s -> System.out.println("It's a square");
case Pentagon p -> System.out.println("It's a pentagon");
}
}
Shape will always match first
Triangle, Square, Pentagon cases
are unreachable
31. 33
Pattern Dominance
void shapeTester(Shape shape) {
switch (shape) {
case Triangle t -> System.out.println("It's a small triangle");
case Triangle t && t.area() > 25 -> System.out.println("It's a big triangle");
case Square s -> System.out.println("It's a square");
case Pentagon p -> System.out.println("It's a pentagon");
case Shape s -> System.out.println("It's a shape");
}
}
Again, Triangle will match before
Triangle with a guard
33. 35
Pattern Matching instanceof And Records
• What we can do now
• This is good but we can do better
record Point(double x, double y) { }
public void pythagoras(Object o) {
if (o instanceof Point p) {
double x = p.x();
double y = p.y();
System.out.println("Hypotonuse = " + Math.sqrt((x*x) + (y*y));
}
}
34. 36
Pattern Matching For Records (JEP 405)
• Use of a record pattern (which is a deconstruction pattern)
• Since a Record is just a special form of class, this will work with normal classes as well
public void pythagoras(Object o) {
if (o instanceof Point(double x, double y))
System.out.println("Hypotonuse = " + Math.sqrt((x*x) + (y*y));
}
35. 37
Patterns Are Composable
record Point(double x, double y) {};
enum Colour { RED, GREEN, BLUE };
record ColourPoint(Point p, Colour c) {};
record ColourRectangle(ColourPoint topLeft,
ColourPoint bottomRight) implements Shape { ... };
public void printColour(Shape s) {
if (s instanceof ColourRectangle(ColourPoint topleft, ColourPoint bottomRight))
System.out.println(topLeft.c());
}
But this is a record as well
36. 38
Patterns Are Composable
public void printColour(Shape s) {
if (s instanceof ColourRectangle(ColourPoint(Point p, Colour c), ColourPoint br))
System.out.println(c);
}
public void printTopLeftX(Shape s) {
if (s instanceof
ColourRectangle(ColourPoint(Point(double x, double y), Colour c), ColourPoint br)
System.out.println(x);
}
Yet another record
37. 39
Patterns And Local Variable Type Inference
• Use var, introduced in JDK 10
• An example of the any pattern matching type
public void printTopLeftX(Shape s) {
if (s instanceof
ColourRectangle(ColourPoint(Point(var x, var y), var c), var br)
System.out.println(x);
}
38. 40
Using The Any Pattern Match
• Not yet part of any proposed JEP
• Related to JEP 302, Lambda Leftovers
• This is not a proposed change, at this time (i.e. I'm speculating this as a feature)
public void printTopLeftX(Shape s) {
if (s instanceof
ColourRectangle(ColourPoint(Point(var x, _), _), _)
System.out.println(x);
}
We have no interest in these
variables so let's ignore them
39. 41
Pattern Matching For Arrays
• Why not use a decompose pattern for arrays?
• This was part of JEP 405 but has been dropped for now
static void printFirstTwoStrings(Object o) {
if (o instanceof String[] sa && sa.length >= 2) {
String s1 = sa[0];
String s2 = sa[1];
System.out.println(s1 + s2);
}
}
static void printFirstTwoStrings(Object o) {
if (o instanceof String[] { String s1, String s2, ... })
System.out.println(s1 + s2);
}
41. 43
Conclusions
• Pattern matching is a powerful set of language constructs
• Simplifies certain tasks
o Less boilerplate code
o More declarative
• Also has the potential for better optimisation of code and enhanced performance
• Some features already included
• More to come
• Yet more may be added later
42. 44
Azul Zulu Builds of OpenJDK
• Enhanced build of OpenJDK source code
o Fully TCK tested
o JDK 7, 8, 11, 13, 15 and 17
o JDK 6 available for commercial customers
• Wide platform support:
o Intel 64-bit Windows, Mac, Linux
o Intel 32-bit Windows and Linux
• Free community edition, optional commercial support (Azul Platform Core)