At first it seemed to be just a small enhancement: the addition of “Pattern Matching for instanceof” (JEP 305) in Java 14. No more unnecessary casting after an instanceof, that ought to save us a few seconds a day! However, upon further investigation you’ll quickly discover that pattern matching is not just an enhancement, but rather a vital puzzle piece in the grander scheme of things.
Why were switch expressions added to Java, for example? To make them support pattern matching in a later release! And why did Java 14 bring us records and will Java 15 contain sealed types? Because they could work really well with pattern matching in a later release! These new concepts are the foundation upon which advanced pattern matching features will be built.
So attend this session to get all caught up! You’ll hear about type patterns, deconstruction patterns, nested patterns and even how pattern matching could improve serialization in the future. Live coding included, of course!
4. #DWX22 #PatternMatching @hannotify @PeterWessels
Small Enhancement
Small Enhancement
Small Enhancement
Small Enhancement
Small Enhancement
https://gph.is/g/ZPJNoPQ
5. #DWX22 #PatternMatching @hannotify @PeterWessels
Major Feature
Major Feature
Major Feature
Major Feature
Major Feature
https://thumbs.gfycat.com/DefiantElasticGadwall.webp
6. #DWX22 #PatternMatching @hannotify @PeterWessels
Pattern
Pattern
Pattern
Pattern
Pattern
Matching for
Matching for
Matching for
Matching for
Matching for
instanceof
instanceof
instanceof
instanceof
instanceof
https://pxhere.com/en/photo/752901
9. #DWX22 #PatternMatching @hannotify @PeterWessels
Instanceof-and-cast
Instanceof-and-cast
if (product instanceof Guitar) { // 1. is product a Guitar?
1
Guitar lesPaul =
2
(Guitar) product;
3
// use lesPaul
4
}
5
10. #DWX22 #PatternMatching @hannotify @PeterWessels
Instanceof-and-cast
Instanceof-and-cast
(Guitar) product; // 2. perform conversion
if (product instanceof Guitar) { // 1. is product a Guitar?
1
Guitar lesPaul =
2
3
// use lesPaul
4
}
5
11. #DWX22 #PatternMatching @hannotify @PeterWessels
Instanceof-and-cast
Instanceof-and-cast
Guitar lesPaul = // 3. declare variable, bind value
if (product instanceof Guitar) { // 1. is product a Guitar?
1
2
(Guitar) product; // 2. perform conversion
3
// use lesPaul
4
}
5
12. #DWX22 #PatternMatching @hannotify @PeterWessels
Improve the situation
Improve the situation
if (product instanceof Guitar) { // 1. is product a Guitar?
Guitar lesPaul = // 3. declare variable, bind value
(Guitar) product; // 2. perform conversion
// use lesPaul
}
1
2
3
4
5
13. #DWX22 #PatternMatching @hannotify @PeterWessels
Improve the situation
Improve the situation
if (product instanceof Guitar lesPaul) {
1
2 // use lesPaul
3 }
14. #DWX22 #PatternMatching @hannotify @PeterWessels
Type pattern
Type pattern
Type pattern
Type pattern
Type pattern
Consists of a predicate that specifies a type,
along with a single binding variable.
https://www.pexels.com/photo/person-holding-white-chalk-625219/
15. #DWX22 #PatternMatching @hannotify @PeterWessels
Pattern matching
Pattern matching
Pattern matching
Pattern matching
Pattern matching
Allows the conditional extraction of
components from objects to be expressed more
concisely and safely.
https://www.pexels.com/photo/person-holding-white-chalk-625219/
17. #DWX22 #PatternMatching @hannotify @PeterWessels
Declaring 'in the middle'
Declaring 'in the middle'
if (product instanceof Guitar lesPaul) {
// use lesPaul
}
1
2
3
18. #DWX22 #PatternMatching @hannotify @PeterWessels
Scoping
Scoping
Pattern binding variable ('flow scoping')
Pattern binding variable ('flow scoping')
The set of places where it would definitely be assigned.
if (product instanceof Guitar lesPaul && lesPaul.isInTune()) {
// can use lesPaul here
} else {
// can't use lesPaul here
}
1
2
3
4
5
20. #DWX22 #PatternMatching @hannotify @PeterWessels
It's a kind of Pattern
It's a kind of Pattern
It's a kind of Pattern
It's a kind of Pattern
It's a kind of Pattern
pattern example
type pattern Guitar lesPaul
https://thumbs.gfycat.com/DefiantElasticGadwall.webp
21. #DWX22 #PatternMatching @hannotify @PeterWessels
Feature Status
Feature Status
Type Patterns
Type Patterns
Java version Feature status JEP
14 Preview
15 Second preview
16 Final
JEP 305
JEP 375
JEP 394
22. #DWX22 #PatternMatching @hannotify @PeterWessels
Pattern
Pattern
Pattern
Pattern
Pattern
Matching for
Matching for
Matching for
Matching for
Matching for
switch
switch
switch
switch
switch
https://pxhere.com/en/photo/752901
31. #DWX22 #PatternMatching @hannotify @PeterWessels
Switch expression
Switch expression
case Delay de -> String.format("Delay active of %d ms.", de.getTimeInMs());
case Reverb re -> String.format("Reverb active of type %s and roomSize %d.", re
String apply(Effect effect) {
1
return switch(effect) {
2
3
4
5 default -> String.format("Unknown effect active: %s.", effect);
6 };
7 }
32. #DWX22 #PatternMatching @hannotify @PeterWessels
Switch expression
Switch expression
1 String apply(Effect effect) {
2 return switch(effect) {
3 case Delay de -> String.format("Delay active of %d ms.", de.getTimeInMs());
4 case Reverb re -> String.format("Reverb active of type %s and roomSize %d.", r
5 case Overdrive ov -> String.format("Overdrive active with gain %d.", ov.getGain()
6 case Tremolo tr -> String.format("Tremolo active with depth %d and rate %d.", t
7 case Tuner tu -> String.format("Tuner active with pitch %d. Muting all signal
8 default -> String.format("Unknown effect active: %s.", effect);
9 };
10 }
33. #DWX22 #PatternMatching @hannotify @PeterWessels
Switch expression
Switch expression
case EffectLoop el -> el.getEffects().stream().map(this::apply).collect(Collectors
String apply(Effect effect) {
1
return switch(effect) {
2
case Delay de -> String.format("Delay active of %d ms.", de.getTimeInMs());
3
case Reverb re -> String.format("Reverb active of type %s and roomSize %d.", r
4
case Overdrive ov -> String.format("Overdrive active with gain %d.", ov.getGain()
5
case Tremolo tr -> String.format("Tremolo active with depth %d and rate %d.", t
6
case Tuner tu -> String.format("Tuner active with pitch %d. Muting all signal
7
8
9 default -> String.format("Unknown effect active: %s.", effect);
10 };
11 }
34. #DWX22 #PatternMatching @hannotify @PeterWessels
Switch expression
Switch expression
String apply(Effect effect) {
return switch(effect) {
case Delay de -> String.format("Delay active of %d ms.", de.getTimeInMs());
case Reverb re -> String.format("Reverb active of type %s and roomSize %d.", r
case Overdrive ov -> String.format("Overdrive active with gain %d.", ov.getGain()
case Tremolo tr -> String.format("Tremolo active with depth %d and rate %d.", t
case Tuner tu -> String.format("Tuner active with pitch %d. Muting all signal
case EffectLoop el -> el.getEffects().stream().map(this::apply).collect(Collectors
default -> String.format("Unknown effect active: %s.", effect);
};
}
1
2
3
4
5
6
7
8
9
10
11
36. #DWX22 #PatternMatching @hannotify @PeterWessels
Sensible operations to the effect loop
Sensible operations to the effect loop
apply()
setVolume(int volume)
contains(Effect... effect)
37. #DWX22 #PatternMatching @hannotify @PeterWessels
Nonsensical operations to the effect
Nonsensical operations to the effect
loop
loop
isTunerActive()
isDelayTimeEqualToReverbRoomSize()
isToneSuitableToPlayPrideInTheNameOfLove()
38. #DWX22 #PatternMatching @hannotify @PeterWessels
Switch expression
Switch expression
String apply(Effect effect) {
return switch(effect) {
case Delay de -> String.format("Delay active of %d ms.", de.getTimeInMs());
case Reverb re -> String.format("Reverb active of type %s and roomSize %d.", r
case Overdrive ov -> String.format("Overdrive active with gain %d.", ov.getGain()
case Tremolo tr -> String.format("Tremolo active with depth %d and rate %d.", t
case Tuner tu -> String.format("Tuner active with pitch %d. Muting all signal
case EffectLoop el -> el.getEffects().stream().map(this::apply).collect(Collectors
default -> String.format("Unknown effect active: %s.", effect);
};
}
1
2
3
4
5
6
7
8
9
10
11
39. #DWX22 #PatternMatching @hannotify @PeterWessels
Switch expression
Switch expression
static String apply(Effect effect) {
return switch(effect) {
case Delay de -> String.format("Delay active of %d ms.", de.getTimeInMs());
case Reverb re -> String.format("Reverb active of type %s and roomSize %d.", r
case Overdrive ov -> String.format("Overdrive active with gain %d.", ov.getGain()
case Tremolo tr -> String.format("Tremolo active with depth %d and rate %d.", t
case Tuner tu -> String.format("Tuner active with pitch %d. Muting all signal
case EffectLoop el -> el.getEffects().stream().map(Effect::apply).collect(Collecto
default -> String.format("Unknown effect active: %s.", effect);
};
}
1
2
3
4
5
6
7
8
9
10
11
40. #DWX22 #PatternMatching @hannotify @PeterWessels
Benefits of pattern matching
Benefits of pattern matching
No need for the Visitor pattern or a common supertype
A single expression instead of many assignments
Less error-prone (in adding cases)
More concise
Safer - the compiler can check for missing cases
41. #DWX22 #PatternMatching @hannotify @PeterWessels
But what if
But what if effect
effect is
is null
null?
?
return switch(effect) { // throws NullPointerException!
static String apply(Effect effect) {
1
2
case Delay de -> String.format("Delay active of %d ms.", de.getTimeInMs());
3
case Reverb re -> String.format("Reverb active of type %s and roomSize %d.", r
4
case Overdrive ov -> String.format("Overdrive active with gain %d.", ov.getGain()
5
case Tremolo tr -> String.format("Tremolo active with depth %d and rate %d.", t
6
case Tuner tu -> String.format("Tuner active with pitch %d. Muting all signal
7
case EffectLoop el -> el.getEffects().stream().map(Effect::apply).collect(Collecto
8
default -> String.format("Unknown effect active: %s.", effect);
9
};
10
}
11
42. #DWX22 #PatternMatching @hannotify @PeterWessels
Combining case labels
Combining case labels
case null, default -> String.format("Unknown or malfunctioning effect active: %s."
static String apply(Effect effect) {
1
return switch(effect) {
2
case Delay de -> String.format("Delay active of %d ms.", de.getTimeInMs());
3
case Reverb re -> String.format("Reverb active of type %s and roomSize %d.", r
4
case Overdrive ov -> String.format("Overdrive active with gain %d.", ov.getGain()
5
case Tremolo tr -> String.format("Tremolo active with depth %d and rate %d.", t
6
case Tuner tu -> String.format("Tuner active with pitch %d. Muting all signal
7
case EffectLoop el -> el.getEffects().stream().map(Effect::apply).collect(Collecto
8
9
};
10
}
11
44. #DWX22 #PatternMatching @hannotify @PeterWessels
Guarded patterns
Guarded patterns
String apply(Effect effect, Guitar guitar) {
return switch(effect) {
// (...)
case Tremolo tr -> String.format("Tremolo active with depth %d and rate %d.", tr.ge
case Tuner tu -> String.format("Tuner active with pitch %d. Muting all signal!", tu
case EffectLoop el -> el.getEffects().stream().map(this::apply).collect(Collectors.
default -> String.format("Unknown effect active: %s.", effect);
};
}
1
2
3
4
5
6
7
8
9
45. #DWX22 #PatternMatching @hannotify @PeterWessels
Guarded patterns
Guarded patterns
case Tuner tu && !tu.isInTune(guitar) -> String.format("Guitar is in need of tuning
String apply(Effect effect, Guitar guitar) {
1
return switch(effect) {
2
// (...)
3
case Tremolo tr -> String.format("Tremolo active with depth %d and rate %d.", tr.ge
4
5
case EffectLoop el -> el.getEffects().stream().map(this::apply).collect(Collectors.
6
default -> String.format("Unknown effect active: %s.", effect);
7
};
8
}
9
46. #DWX22 #PatternMatching @hannotify @PeterWessels
Guarded patterns
Guarded patterns
case Tuner tu when !tu.isInTune(guitar) -> String.format("Guitar is in need of tuni
String apply(Effect effect, Guitar guitar) {
1
return switch(effect) {
2
// (...)
3
case Tremolo tr -> String.format("Tremolo active with depth %d and rate %d.", tr.ge
4
5
case EffectLoop el -> el.getEffects().stream().map(this::apply).collect(Collectors.
6
default -> String.format("Unknown effect active: %s.", effect);
7
};
8
}
9
47. #DWX22 #PatternMatching @hannotify @PeterWessels
Guarded patterns
Guarded patterns
switch(effect) {
// ...
case Tuner tu:
if (!tu.isInTune(guitar)) { // tuning is needed }
else { // no tuning is needed }
break;
// ...
}
1
2
3
4
5
6
7
8
48. #DWX22 #PatternMatching @hannotify @PeterWessels
It's a kind of Pattern
It's a kind of Pattern
It's a kind of Pattern
It's a kind of Pattern
It's a kind of Pattern
pattern example
guarded pattern Tuner tu when
!tu.isInTune(guitar)
type pattern Guitar lesPaul
https://thumbs.gfycat.com/DefiantElasticGadwall.webp
49. #DWX22 #PatternMatching @hannotify @PeterWessels
Feature Status
Feature Status
Guarded Patterns
Guarded Patterns
Java version Feature status JEP
17 Preview
18 Second preview
19 Third preview
JEP 406
JEP 420
JEP 427
51. #DWX22 #PatternMatching @hannotify @PeterWessels
Disclaimer
Disclaimer
Disclaimer
Disclaimer
Disclaimer
We can't tell you when the following features
are coming to Java. Also: syntax and
implementation specifics may still change.
https://pxhere.com/en/photo/1359311
52. #DWX22 #PatternMatching @hannotify @PeterWessels
Deconstruction patterns
Deconstruction patterns
String apply(Effect effect) {
return switch(effect) {
case Delay de -> String.format("Delay active of %d ms.", de.getTimeInMs());
case Reverb re -> String.format("Reverb active of type %s and roomSize %d.", r
case Overdrive ov -> String.format("Overdrive active with gain %d.", ov.getGain()
case Tremolo tr -> String.format("Tremolo active with depth %d and rate %d.", t
case Tuner tu -> String.format("Tuner active with pitch %d. Muting all signal
case EffectLoop el -> el.getEffects().stream().map(this::apply).collect(Collectors
default -> String.format("Unknown effect active: %s.", effect);
};
}
1
2
3
4
5
6
7
8
9
10
11
53. #DWX22 #PatternMatching @hannotify @PeterWessels
Deconstruction patterns
Deconstruction patterns
case Overdrive(int gain) -> String.format("Overdrive active with gain %d.", gain);
String apply(Effect effect) {
1
return switch(effect) {
2
case Delay de -> String.format("Delay active of %d ms.", de.getTimeInMs());
3
case Reverb re -> String.format("Reverb active of type %s and roomSize %d.", r
4
5
case Tremolo tr -> String.format("Tremolo active with depth %d and rate %d.", t
6
case Tuner tu -> String.format("Tuner active with pitch %d. Muting all signal
7
case EffectLoop el -> el.getEffects().stream().map(this::apply).collect(Collectors
8
default -> String.format("Unknown effect active: %s.", effect);
9
};
10
}
11
54. #DWX22 #PatternMatching @hannotify @PeterWessels
Pattern definition
Pattern definition
public class Overdrive implements Effect {
private final int gain;
public Overdrive(int gain) {
this.gain = gain;
}
}
1
2
3
4
5
6
7
55. #DWX22 #PatternMatching @hannotify @PeterWessels
Pattern definition
Pattern definition
1 public class Overdrive implements Effect {
2 private final int gain;
3
4 public Overdrive(int gain) {
5 this.gain = gain;
6 }
7
public pattern Overdrive(int gain) {
8
gain = this.gain;
9
}
10
11 }
56. #DWX22 #PatternMatching @hannotify @PeterWessels
Deconstruction patterns
Deconstruction patterns
case Overdrive(int gain) -> String.format("Overdrive active with gain %d.", gain);
String apply(Effect effect) {
1
return switch(effect) {
2
case Delay de -> String.format("Delay active of %d ms.", de.getTimeInMs());
3
case Reverb re -> String.format("Reverb active of type %s and roomSize %d.", r
4
5
case Tremolo tr -> String.format("Tremolo active with depth %d and rate %d.", t
6
case Tuner tu -> String.format("Tuner active with pitch %d. Muting all signal
7
case EffectLoop el -> el.getEffects().stream().map(this::apply).collect(Collectors
8
default -> String.format("Unknown effect active: %s.", effect);
9
};
10
}
11
58. #DWX22 #PatternMatching @hannotify @PeterWessels
Deconstruction patterns
Deconstruction patterns
String apply(Effect effect) {
return switch(effect) {
case Delay(int timeInMs) -> String.format("Delay active of %d ms.", timeInMs);
case Reverb(String name, int roomSize) -> String.format("Reverb active of type %s
case Overdrive(int gain) -> String.format("Overdrive active with gain %d.", gain);
case Tremolo(int depth, int rate) -> String.format("Tremolo active with depth %d a
case Tuner(int pitchInHz) -> String.format("Tuner active with pitch %d. Muting all
case EffectLoop(Set<Effect> effects) -> effects.stream().map(this::apply).collect(
default -> String.format("Unknown effect active: %s.", effect);
};
}
1
2
3
4
5
6
7
8
9
10
11
59. #DWX22 #PatternMatching @hannotify @PeterWessels
Can we combine patterns?
Can we combine patterns?
static boolean isDelayTimeEqualToReverbRoomSize(EffectLoop effectLoop) {
}
1
2
3
62. #DWX22 #PatternMatching @hannotify @PeterWessels
It's a kind of Pattern
It's a kind of Pattern
It's a kind of Pattern
It's a kind of Pattern
It's a kind of Pattern
pattern example
deconstruction pattern Delay(int timeInMs)
type pattern Guitar lesPaul
guarded pattern Tuner tu when
!tu.isInTune(guitar)
https://thumbs.gfycat.com/DefiantElasticGadwall.webp
63. #DWX22 #PatternMatching @hannotify @PeterWessels
Var and any patterns
Var and any patterns
// Pre-Java 10
Guitar telecaster = new Guitar("Fender Telecaster Baritone Blacktop", GuitarType.TELECASTER
// Java 10
var telecaster = new Guitar("Fender Telecaster Baritone Blacktop", GuitarType.TELECASTER);
1
2
3
4
5
https://openjdk.java.net/jeps/286
https://openjdk.java.net/jeps/286
64. #DWX22 #PatternMatching @hannotify @PeterWessels
Var and any patterns
Var and any patterns
static boolean isDelayTimeEqualToReverbRoomSize(EffectLoop effectLoop) {
if (effectLoop instanceof EffectLoop(Delay(int timeInMs), Reverb(String name, int roomS
return timeInMs == roomSize;
}
return false;
}
1
2
3
4
5
6
65. #DWX22 #PatternMatching @hannotify @PeterWessels
Var and any patterns
Var and any patterns
if (effectLoop instanceof EffectLoop(Delay(var timeInMs), Reverb(var name, var roomSize
static boolean isDelayTimeEqualToReverbRoomSize(EffectLoop effectLoop) {
1
2
return timeInMs == roomSize;
3
}
4
return false;
5
}
6
67. #DWX22 #PatternMatching @hannotify @PeterWessels
Var and any patterns
Var and any patterns
static boolean isDelayTimeEqualToReverbRoomSize(EffectLoop effectLoop) {
if (effectLoop instanceof EffectLoop(Delay(var timeInMs), Reverb(_, var roomSize))) {
return timeInMs == roomSize;
}
return false;
}
1
2
3
4
5
6
68. #DWX22 #PatternMatching @hannotify @PeterWessels
Optimization
Optimization
static String apply(Effect effect) {
return switch(effect) {
case Delay(int timeInMs) -> String.format("Delay active of %d ms.", timeInMs);
case Reverb(String name, int roomSize) -> String.format("Reverb active of type %s
case Overdrive(int gain) -> String.format("Overdrive active with gain %d.", gain);
case Tremolo(int depth, int rate) -> String.format("Tremolo active with depth %d a
case Tuner(int pitchInHz) -> String.format("Tuner active with pitch %d. Muting all
case EffectLoop(var effects) -> effects.stream().map(Effect::apply).collect(Collec
default -> String.format("Unknown effect active: %s.", effect);
};
}
1
2
3
4
5
6
7
8
9
10
11
71. #DWX22 #PatternMatching @hannotify @PeterWessels
Benefits
Benefits
Better encapsulation
a case branch only receives data that it actually references.
More elegant logic
by using pattern composition
Optimization
through the use of any patterns
72. #DWX22 #PatternMatching @hannotify @PeterWessels
It's a kind of Pattern
It's a kind of Pattern
It's a kind of Pattern
It's a kind of Pattern
It's a kind of Pattern
pattern example
var pattern var timeInMs
type pattern Guitar lesPaul
guarded pattern Tuner tu when
!tu.isInTune(guitar)
deconstruction pattern Delay(int timeInMs)
https://thumbs.gfycat.com/DefiantElasticGadwall.webp
73. #DWX22 #PatternMatching @hannotify @PeterWessels
It's a kind of Pattern
It's a kind of Pattern
It's a kind of Pattern
It's a kind of Pattern
It's a kind of Pattern
pattern example
any pattern _
type pattern Guitar lesPaul
guarded pattern Tuner tu when
!tu.isInTune(guitar)
deconstruction pattern Delay(int timeInMs)
var pattern var timeInMs
https://thumbs.gfycat.com/DefiantElasticGadwall.webp
74. #DWX22 #PatternMatching @hannotify @PeterWessels
Feature Status
Feature Status
Java
version
Feature status JEP
19 Preview (composition of record and type
patterns only)
JEP
405
75. #DWX22 #PatternMatching @hannotify @PeterWessels
Pattern Matching Plays Nice
Pattern Matching Plays Nice
With
With
Sealed Types
Sealed Types
Sealed Types
Sealed Types
Sealed Types
and Records
and Records
and Records
and Records
and Records
https://pxhere.com/en/photo/752901
77. #DWX22 #PatternMatching @hannotify @PeterWessels
Sealed types yield completeness
Sealed types yield completeness
static String apply(Effect effect) {
return switch(effect) {
case Delay(int timeInMs) -> String.format("Delay active of %d ms.", timeInMs);
case Reverb(String name, int roomSize) -> String.format("Reverb active of type %s
case Overdrive(int gain) -> String.format("Overdrive active with gain %d.", gain);
case Tremolo(int depth, int rate) -> String.format("Tremolo active with depth %d a
case Tuner(int pitchInHz) -> String.format("Tuner active with pitch %d. Muting all
case EffectLoop(Tuner(int pitchInHz), _) -> String.format("The EffectLoop contains
case EffectLoop(var effects) -> effects.stream().map(Effect::apply).collect(Collec
default -> String.format("Unknown effect active: %s.", effect);
};
}
1
2
3
4
5
6
7
8
9
10
11
12
78. #DWX22 #PatternMatching @hannotify @PeterWessels
Sealed types yield completeness
Sealed types yield completeness
static String apply(Effect effect) {
return switch(effect) {
case Delay(int timeInMs) -> String.format("Delay active of %d ms.", timeInMs);
case Reverb(String name, int roomSize) -> String.format("Reverb active of type %s
case Overdrive(int gain) -> String.format("Overdrive active with gain %d.", gain);
case Tremolo(int depth, int rate) -> String.format("Tremolo active with depth %d a
case Tuner(int pitchInHz) -> String.format("Tuner active with pitch %d. Muting all
case EffectLoop(Tuner(int pitchInHz), _) -> String.format("The EffectLoop contains
case EffectLoop(var effects) -> effects.stream().map(Effect::apply).collect(Collec
1
2
3
4
5
6
7
8
9
10 };
11 }
https://cr.openjdk.java.net/~briangoetz/amber/pattern-match.html
79. #DWX22 #PatternMatching @hannotify @PeterWessels
Records
Records
Input:
Input:
Commit to the class being a transparent carrier for its data.
Output:
Output:
constructors
accessor methods
equals()-implementation
hashCode()-implementation
toString()-implementation
deconstruction pattern
80. #DWX22 #PatternMatching @hannotify @PeterWessels
Array patterns
Array patterns
record EffectLoop(String name, int volume, Effect... effects) { }
1
static String apply(EffectLoop effectLoop) {}
return switch(effectLoop) {
case EffectLoop(var name, var volume) -> "Effect loop contains no effects.";
}
}
1
2
3
4
5
81. #DWX22 #PatternMatching @hannotify @PeterWessels
Array patterns
Array patterns
record EffectLoop(String name, int volume, Effect... effects) { }
1
static String apply(EffectLoop effectLoop) {}
return switch(effectLoop) {
case EffectLoop(var name, var volume) -> "Effect loop contains no effects.";
case EffectLoop(_, _, var effect) -> "Effect loop contains exactly one effect.";
1
2
3
4
5 }
6 }
82. #DWX22 #PatternMatching @hannotify @PeterWessels
Array patterns
Array patterns
record EffectLoop(String name, int volume, Effect... effects) { }
1
static String apply(EffectLoop effectLoop) {}
return switch(effectLoop) {
case EffectLoop(var name, var volume) -> "Effect loop contains no effects.";
case EffectLoop(_, _, var effect) -> "Effect loop contains exactly one effect.";
case EffectLoop(_, _, var effect, ...) -> "Effect loop contains more than one effec
1
2
3
4
5
6 }
7 }
83. #DWX22 #PatternMatching @hannotify @PeterWessels
Array patterns
Array patterns
record EffectLoop(String name, int volume, Effect... effects) { }
1
static String apply(EffectLoop effectLoop) {}
return switch(effectLoop) {
case EffectLoop(var name, var volume) -> "Effect loop contains no effects.";
case EffectLoop(_, _, var effect) -> "Effect loop contains exactly one effect.";
case EffectLoop(_, _, var effect, ...) -> "Effect loop contains more than one effec
case EffectLoop(_, _, var effect1, var effect2) -> "Effect loop contains exactly tw
case EffectLoop(_, _, var effect1, var effect2, ...) -> "Effect loop contains more
1
2
3
4
5
6
7
8 }
9 }
84. #DWX22 #PatternMatching @hannotify @PeterWessels
It's a kind of Pattern
It's a kind of Pattern
It's a kind of Pattern
It's a kind of Pattern
It's a kind of Pattern
pattern example
array pattern EffectLoop(var name, var effect, ...)
.. ..
var pattern var timeInMs
any pattern _
https://thumbs.gfycat.com/DefiantElasticGadwall.webp
85. #DWX22 #PatternMatching @hannotify @PeterWessels
Feature Status
Feature Status
Sealed Types
Sealed Types
Java version Feature status JEP
15 Preview
16 Second preview
17 Final
JEP 360
JEP 397
JEP 409
86. #DWX22 #PatternMatching @hannotify @PeterWessels
Feature Status
Feature Status
Completeness
Completeness
Java version Feature status JEP
17 Preview
18 Second preview
19 Third preview
JEP 406
JEP 420
JEP 427
87. #DWX22 #PatternMatching @hannotify @PeterWessels
Feature Status
Feature Status
Record Patterns
Record Patterns
Java version Feature status JEP
19 Preview JEP 405
88. #DWX22 #PatternMatching @hannotify @PeterWessels
A Better
A Better
A Better
A Better
A Better
Serialization?
Serialization?
Serialization?
Serialization?
Serialization?
https://pxhere.com/en/photo/752901
89. #DWX22 #PatternMatching @hannotify @PeterWessels
Here be dragons!
Here be dragons!
Here be dragons!
Here be dragons!
Here be dragons!
We can't be sure at all that the following
features will appear in Java as depicted. They
can change a lot in the meantime.
https://www.pexels.com/photo/dragon-festival-during-nighttime-6068535/
90. #DWX22 #PatternMatching @hannotify @PeterWessels
Opposites
Opposites
Deconstruction pattern
Deconstruction pattern
transforms an object into a set of typed fields
Constructor
Constructor
transforms a set of typed fields into an object
91. #DWX22 #PatternMatching @hannotify @PeterWessels
Serialization
Serialization
very important feature
but many people hate its current implementation
Drawbacks
Drawbacks
it undermines the accessibility model
serialization logic is not 'readable code'
it bypasses constructors and data validation
96. #DWX22 #PatternMatching @hannotify @PeterWessels
Some challenges remain
Some challenges remain
Q:
Q: How to support multiple versions of one class?
How to support multiple versions of one class?
A: @Serializer and @Deserializer annotations could get a
property version in the future.
97. #DWX22 #PatternMatching @hannotify @PeterWessels
Feature Status
Feature Status
Java
version
Feature status JEP
n/a Exploratory
document
Towards Better
Serialization
https://cr.openjdk.java.net/~briangoetz/amber/serialization.html
99. #DWX22 #PatternMatching @hannotify @PeterWessels
Here be super dragons!
Here be super dragons!
Here be super dragons!
Here be super dragons!
Here be super dragons!
We can't be sure that the following features will
appear in Java as depicted, if at all.
Proceed with caution!
https://www.pexels.com/photo/dragon-festival-during-nighttime-6068535/
100. #DWX22 #PatternMatching @hannotify @PeterWessels
Pattern bind statements
Pattern bind statements
var reverb = new Reverb("ChamberReverb", 2);
__let Reverb(String name, int roomSize) = reverb;
// do something with name & roomSize
1
2
3
4
5
https://cr.openjdk.java.net/~briangoetz/amber/pattern-match.html
101. #DWX22 #PatternMatching @hannotify @PeterWessels
Pattern bind statements
Pattern bind statements
else throw new IllegalArgumentException("not a Reverb!");
var reverb = new Reverb("ChamberReverb", 2);
1
2
__let Reverb(String name, int roomSize) = reverb;
3
4
5
6 // do something with name & roomSize
102. #DWX22 #PatternMatching @hannotify @PeterWessels
Other ideas
Other ideas
AND patterns:
PatternOne&PatternTwo
Patterns in catch clauses:
(will most likely complement multi-catch blocks)
Collection patterns
https://mail.openjdk.java.net/pipermail/amber-spec-experts/2021-January/002758.html
https://mail.openjdk.java.net/pipermail/amber-spec-experts/2021-January/002758.html
104. #DWX22 #PatternMatching @hannotify @PeterWessels
Pattern Contexts
Pattern Contexts
Pattern context Example Purpose
instanceof
predicate
product instanceof Guitar
guitar
Test if target matches the indicated
pattern.
switch statement
or expression
switch (effect) {
case Delay d ->
}
Test if target matches one (or more)
of the indicated patterns.
bind statement __let Reverb(var name, var
roomSize) = reverb;
Destructure a target using a pattern.
106. #DWX22 #PatternMatching @hannotify @PeterWessels
Pattern matching...
Pattern matching...
is a rich feature arc that will play out over several versions.
allows us to use type patterns in instanceof.
improves switch expressions.
makes destructuring objects as easy as (and more similar to)
constructing them.
holds the potential to simplify and streamline much of the code
we write today.