SlideShare ist ein Scribd-Unternehmen logo
1 von 105
Downloaden Sie, um offline zu lesen
Pattern
Pattern
Pattern
Pattern
Pattern
Pattern
Pattern
Pattern
Pattern
Pattern
Pattern
Pattern
Matching
Matching
Matching
Matching
Matching
Matching
Matching
Matching
Matching
Matching
Matching
Matching
From Small Enhancement to Major Feature
From Small Enhancement to Major Feature
Hanno Embregts



@hannotify
Small Enhancement
Small Enhancement
Small Enhancement
Small Enhancement
Small Enhancement
https://gph.is/g/ZPJNoPQ
Major Feature
Major Feature
Major Feature
Major Feature
Major Feature
https://thumbs.gfycat.com/DefiantElasticGadwall.webp
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
https://pxhere.com/en/photo/548063
Instanceof-and-cast
Instanceof-and-cast
if (product instanceof Guitar) {
Guitar lesPaul =
(Guitar) product;
// use lesPaul
}
1
2
3
4
5
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
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
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
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
Improve the situation
Improve the situation
if (product instanceof Guitar lesPaul) {
// use lesPaul
}
1
2
3
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/
Declaring 'in the
Declaring 'in the
middle'
middle'
if (product instanceof Guitar lesPaul) {
// use lesPaul
}
1
2
3
Scoping
Scoping
'Regular' local variable ('block scoping')
'Regular' local variable ('block scoping')
The block in which it is declared.
void playTunedGuitar() {
Guitar lesPaul = new Guitar("Les Paul");
if (!lesPaul.isInTune()) {
Guitar fenderStrat = new Guitar("Fender Stratocaster");
fenderStrat.play();
}
}
1
2
3
4
5
6
7
8
Scoping
Scoping
'Regular' local variable ('block scoping')
'Regular' local variable ('block scoping')
The block in which it is declared.
void playTunedGuitar() {
Guitar lesPaul = new Guitar("Les Paul");
if (!lesPaul.isInTune()) {
Guitar fenderStrat = new Guitar("Fender Stratocaster");
fenderStrat.play();
// fenderStrat is in scope
}
// fenderStrat is not in scope
}
1
2
3
4
5
6
7
8
9
10
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) {
// can use lesPaul here
} else {
// can't use lesPaul here
}
1
2
3
4
5
Scoping
Scoping
Pattern binding variable ('flow scoping')
Pattern binding variable ('flow scoping')
The set of places where it would definitely be
assigned.
boolean isTunedGuitar(Object product) {
if (!(product instanceof Guitar lesPaul)) {
return false;
}
// This code is only reachable if 'product' is
// a Guitar, so 'lesPaul' is in scope.
return lesPaul.isInTune();
}
1
2
3
4
5
6
7
8
9
Scoping
Scoping
Pattern binding variable ('flow scoping')
Pattern binding variable ('flow scoping')
The set of places where it would definitely be
assigned.
void test(Effect effect) {
if (effect instanceof Reverb stockEffect)
stockEffect.setRoomSize(25);
else if (effect instanceof Delay stockEffect)
stockEffect.setTimeInMs(200);
}
1
2
3
4
5
6
Demo
Demo
Simplify implementation of equals
https://pxhere.com/en/photo/1458897
Benefits
Benefits
Nearly 100% of casts will just disappear!
More concise
No type repeating
Feature Status
Feature Status
Java version Feature status JEP
14 Preview
15 Second preview
16 Final
JEP 305
JEP 375
JEP 394
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
String apply(Effect effect) {
String formatted = "";
if (effect instanceof Delay) {
Delay de = (Delay) effect;
formatted = String.format("Delay active of %d ms.", de.getTim
} else if (effect instanceof Reverb) {
Reverb re = (Reverb) effect;
formatted = String.format("Reverb active of type %s and roomS
} else if (effect instanceof Overdrive) {
Overdrive ov = (Overdrive) effect;
formatted = String.format("Overdrive active with gain %d.", ov
} else if (effect instanceof Tremolo) {
Tremolo tr = (Tremolo) effect;
formatted = String.format("Tremolo active with depth %d and r
} else if (effect instanceof Tuner) {
Tuner tu = (Tuner) effect;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
formatted = String.format("Delay active of %d ms.", de.getTim
formatted = String.format("Reverb active of type %s and roomS
formatted = String.format("Overdrive active with gain %d.", ov
formatted = String.format("Tremolo active with depth %d and r
String apply(Effect effect) {
1
String formatted = "";
2
if (effect instanceof Delay) {
3
Delay de = (Delay) effect;
4
5
} else if (effect instanceof Reverb) {
6
Reverb re = (Reverb) effect;
7
8
} else if (effect instanceof Overdrive) {
9
Overdrive ov = (Overdrive) effect;
10
11
} else if (effect instanceof Tremolo) {
12
Tremolo tr = (Tremolo) effect;
13
14
} else if (effect instanceof Tuner) {
15
Tuner tu = (Tuner) effect;
16
String apply(Effect effect) {
String formatted = "";
if (effect instanceof Delay de) {
formatted = String.format("Delay active of %d ms.", de.getTim
} else if (effect instanceof Reverb re) {
formatted = String.format("Reverb active of type %s and roomS
} else if (effect instanceof Overdrive ov) {
formatted = String.format("Overdrive active with gain %d.", ov
} else if (effect instanceof Tremolo tr) {
formatted = String.format("Tremolo active with depth %d and r
} else if (effect instanceof Tuner tu) {
formatted = String.format("Tuner active with pitch %d. Muting
} else if (effect instanceof EffectLoop el) {
formatted = el.getEffects().stream().map(this::apply).collect
} else {
formatted = String format("Unknown effect active: %s " effect
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
formatted = String.format("Delay active of %d ms.", de.getTim
formatted = String.format("Reverb active of type %s and roomS
formatted = String.format("Overdrive active with gain %d.", ov
formatted = String.format("Tremolo active with depth %d and r
formatted = String.format("Tuner active with pitch %d. Muting
formatted = el.getEffects().stream().map(this::apply).collect
formatted = String format("Unknown effect active: %s " effect
String apply(Effect effect) {
1
String formatted = "";
2
if (effect instanceof Delay de) {
3
4
} else if (effect instanceof Reverb re) {
5
6
} else if (effect instanceof Overdrive ov) {
7
8
} else if (effect instanceof Tremolo tr) {
9
10
} else if (effect instanceof Tuner tu) {
11
12
} else if (effect instanceof EffectLoop el) {
13
14
} else {
15
16
Switch expression
Switch expression
String apply(Effect effect) {
return switch(effect) {
default -> String.format("Unknown effect active: %s
};
}
1
2
3
4
5
Switch expression
Switch expression
case Delay de -> String.format("Delay active of %d ms.",
case Reverb re -> String.format("Reverb active of type %s
String apply(Effect effect) {
1
return switch(effect) {
2
3
4
default -> String.format("Unknown effect active: %s
5
};
6
}
7
Switch expression
Switch expression
case Overdrive ov -> String.format("Overdrive active with ga
case Tremolo tr -> String.format("Tremolo active with depth
case Tuner tu -> String.format("Tuner active with pitch
String apply(Effect effect) {
1
return switch(effect) {
2
case Delay de -> String.format("Delay active of %d ms.",
3
case Reverb re -> String.format("Reverb active of type %s
4
5
6
7
default -> String.format("Unknown effect active: %
8
};
9
}
10
Switch expression
Switch expression
case EffectLoop el -> el.getEffects().stream().map(this::apply
String apply(Effect effect) {
1
return switch(effect) {
2
case Delay de -> String.format("Delay active of %d ms.",
3
case Reverb re -> String.format("Reverb active of type %s
4
case Overdrive ov -> String.format("Overdrive active with ga
5
case Tremolo tr -> String.format("Tremolo active with depth
6
case Tuner tu -> String.format("Tuner active with pitch
7
8
default -> String.format("Unknown effect active: %
9
};
10
}
11
Switch expression
Switch expression
String apply(Effect effect) {
return switch(effect) {
case Delay de -> String.format("Delay active of %d ms.",
case Reverb re -> String.format("Reverb active of type %s
case Overdrive ov -> String.format("Overdrive active with ga
case Tremolo tr -> String.format("Tremolo active with depth
case Tuner tu -> String.format("Tuner active with pitch
case EffectLoop el -> el.getEffects().stream().map(this::apply
default -> String.format("Unknown effect active: %
};
}
1
2
3
4
5
6
7
8
9
10
11
Sensible operations to the
Sensible operations to the
effect loop
effect loop
apply()
setVolume(int volume)
contains(Effect... effect)
Nonsensical operations to the
Nonsensical operations to the
effect loop
effect loop
isTunerActive()
isDelayTimeEqualToReverbRoomSize()
isToneSuitableToPlayPrideInTheNameOfLov
Visitor pattern
Visitor pattern
interface EffectVisitor<T> {

T visit(Tuner effect);

T visit(Delay effect);

T visit(Reverb effect);

// ...
}

class IsTunerActiveVisitor implements EffectVisitor<Boolean> {

public Boolean visit(Tuner effect) {

return !effect.isInTune();

}
public Boolean visit(Delay effect) { return false; }

public Boolean visit(Reverb effect) { return false; }

// ...
}
Switch expression
Switch expression
String apply(Effect effect) {
return switch(effect) {
case Delay de -> String.format("Delay active of %d ms.",
case Reverb re -> String.format("Reverb active of type %s
case Overdrive ov -> String.format("Overdrive active with ga
case Tremolo tr -> String.format("Tremolo active with depth
case Tuner tu -> String.format("Tuner active with pitch
case EffectLoop el -> el.getEffects().stream().map(this::apply
default -> String.format("Unknown effect active: %
};
}
1
2
3
4
5
6
7
8
9
10
11
Switch expression
Switch expression
static String apply(Effect effect) {
return switch(effect) {
case Delay de -> String.format("Delay active of %d ms.",
case Reverb re -> String.format("Reverb active of type %s
case Overdrive ov -> String.format("Overdrive active with ga
case Tremolo tr -> String.format("Tremolo active with depth
case Tuner tu -> String.format("Tuner active with pitch
case EffectLoop el -> el.getEffects().stream().map(Effect::app
default -> String.format("Unknown effect active: %
};
}
1
2
3
4
5
6
7
8
9
10
11
Benefits
Benefits
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
What happens if
What happens if effect
effect is
is
null
null?
?
static String apply(Effect effect) {
return switch(effect) {
case Delay de -> String.format("Delay active of %d ms.",
case Reverb re -> String.format("Reverb active of type %s
case Overdrive ov -> String.format("Overdrive active with ga
case Tremolo tr -> String.format("Tremolo active with depth
case Tuner tu -> String.format("Tuner active with pitch
case EffectLoop el -> el.getEffects().stream().map(Effect::app
default -> String.format("Unknown effect active: %
};
}
1
2
3
4
5
6
7
8
9
10
11
What happens if
What happens 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.",
3
case Reverb re -> String.format("Reverb active of type %s
4
case Overdrive ov -> String.format("Overdrive active with ga
5
case Tremolo tr -> String.format("Tremolo active with depth
6
case Tuner tu -> String.format("Tuner active with pitch
7
case EffectLoop el -> el.getEffects().stream().map(Effect::app
8
default -> String.format("Unknown effect active: %
9
};
10
}
11
Solution #1: defensive testing
Solution #1: defensive testing
if (effect == null) {
return "Malfunctioning effect active.";
}
static String apply(Effect effect) {
1
2
3
4
5
return switch(effect) {
6
case Delay de -> String.format("Delay active of %d ms.",
7
case Reverb re -> String.format("Reverb active of type %s
8
case Overdrive ov -> String.format("Overdrive active with ga
9
case Tremolo tr -> String.format("Tremolo active with depth
10
case Tuner tu -> String.format("Tuner active with pitch
11
case EffectLoop el -> el.getEffects().stream().map(Effect::app
12
default -> String.format("Unknown effect active: %
13
};
14
}
15
Solution #2: integrate null
Solution #2: integrate null
check in switch
check in switch
case null -> return "Malfunctioning effect active.";
static String apply(Effect effect) {
1
return switch(effect) {
2
3
case Delay de -> String.format("Delay active of %d ms.",
4
case Reverb re -> String.format("Reverb active of type %s
5
case Overdrive ov -> String.format("Overdrive active with ga
6
case Tremolo tr -> String.format("Tremolo active with depth
7
case Tuner tu -> String.format("Tuner active with pitch
8
case EffectLoop el -> el.getEffects().stream().map(Effect::app
9
default -> String.format("Unknown effect active: %
10
};
11
}
12
Combining case labels
Combining case labels
case null, default -> String.format("Unknown or malfunctionin
static String apply(Effect effect) {
1
return switch(effect) {
2
case Delay de -> String.format("Delay active of %d ms.",
3
case Reverb re -> String.format("Reverb active of type %s
4
case Overdrive ov -> String.format("Overdrive active with ga
5
case Tremolo tr -> String.format("Tremolo active with depth
6
case Tuner tu -> String.format("Tuner active with pitch
7
case EffectLoop el -> el.getEffects().stream().map(Effect::app
8
9
};
10
}
11
Guarded patterns
Guarded patterns
String apply(Effect effect, Guitar guitar) {
return switch(effect) {
// (...)
case Tremolo tr-> String.format("Tremolo active with depth %d
case Tuner tu -> String.format("Tuner active with pitch %d. Mu
case EffectLoop el -> el.getEffects().stream().map(this::apply
default -> String.format("Unknown effect active: %s.", effect)
};
}
1
2
3
4
5
6
7
8
9
https://openjdk.java.net/jeps/406
Guarded patterns
Guarded patterns
case Tuner tu && !tu.isInTune(guitar) -> String.format("Guitar
String apply(Effect effect, Guitar guitar) {
1
return switch(effect) {
2
// (...)
3
case Tremolo tr-> String.format("Tremolo active with depth %d
4
5
case EffectLoop el -> el.getEffects().stream().map(this::apply
6
default -> String.format("Unknown effect active: %s.", effect)
7
};
8
}
9
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
Guarded patterns
Guarded patterns
switch(effect) {
// ...
case Tuner tu && !tu.isInTune(guitar) -> // tuning is needed
case Tuner tu -> // no tuning is needed
// ...
}
1
2
3
4
5
6
Feature Status
Feature Status
Java version Feature status JEP
17 Preview JEP 406
https://openjdk.java.net/jeps/406
Deconstruction
Deconstruction
Deconstruction
Deconstruction
Deconstruction
Patterns
Patterns
Patterns
Patterns
Patterns
https://pxhere.com/en/photo/752901
Disclaimer
Disclaimer
Disclaimer
Disclaimer
Disclaimer
I 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
Deconstruction patterns
Deconstruction patterns
static String apply(Effect effect) {
return switch(effect) {
case Delay de -> String.format("Delay active of %d ms.",
case Reverb re -> String.format("Reverb active of type %s
case Overdrive ov -> String.format("Overdrive active with ga
case Tremolo tr -> String.format("Tremolo active with depth
case Tuner tu -> String.format("Tuner active with pitch
case EffectLoop el -> el.getEffects().stream().map(Effect::app
default -> String.format("Unknown effect active: %
};
}
1
2
3
4
5
6
7
8
9
10
11
Deconstruction patterns
Deconstruction patterns
case Overdrive(int gain) -> String.format("Overdrive active w
static String apply(Effect effect) {
1
return switch(effect) {
2
case Delay de -> String.format("Delay active of %d ms.",
3
case Reverb re -> String.format("Reverb active of type %s
4
5
case Tremolo tr -> String.format("Tremolo active with depth
6
case Tuner tu -> String.format("Tuner active with pitch
7
case EffectLoop el -> el.getEffects().stream().map(Effect::app
8
default -> String.format("Unknown effect active: %
9
};
10
}
11
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
Pattern definition
Pattern definition
public pattern Overdrive(int gain) {
gain = this.gain;
}
public class Overdrive implements Effect {
1
private final int gain;
2
3
public Overdrive(int gain) {
4
this.gain = gain;
5
}
6
7
8
9
10
}
11
Deconstruction patterns
Deconstruction patterns
case Overdrive(int gain) -> String.format("Overdrive active w
static String apply(Effect effect) {
1
return switch(effect) {
2
case Delay de -> String.format("Delay active of %d ms.",
3
case Reverb re -> String.format("Reverb active of type %s
4
5
case Tremolo tr -> String.format("Tremolo active with depth
6
case Tuner tu -> String.format("Tuner active with pitch
7
case EffectLoop el -> el.getEffects().stream().map(Effect::app
8
default -> String.format("Unknown effect active: %
9
};
10
}
11
Deconstruction patterns
Deconstruction patterns
static String apply(Effect effect) {
return switch(effect) {
case Delay(int timeInMs) -> String.format("Delay active of %d
case Reverb(String name, int roomSize) -> String.format("Reve
case Overdrive(int gain) -> String.format("Overdrive active w
case Tremolo(int depth, int rate) -> String.format("Tremolo ac
case Tuner(int pitchInHz) -> String.format("Tuner active with
case EffectLoop(Set<Effect> effects) -> effects.stream().map(E
default -> String.format("Unknown effect active: %s.", effect
};
}
1
2
3
4
5
6
7
8
9
10
11
Pattern composition
Pattern composition
static boolean isDelayTimeEqualToReverbRoomSize(EffectLoop effectLoop)
}
1
2
3
Pattern composition
Pattern composition
static boolean isDelayTimeEqualToReverbRoomSize(EffectLoop effectLoop
return effectLoop.getEffects().stream()
.filter(e -> e instanceof Delay || e instanceof Reverb)
.map(dr -> {
if (dr instanceof Delay d) {
return d.getTimeInMs();
} else {
Reverb r = (Reverb) dr;
return r.getRoomSize();
}
}).distinct().count() == 1;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
Pattern composition
Pattern composition
static boolean isDelayTimeEqualToReverbRoomSize(EffectLoop effectLoop)
if (effectLoop instanceof EffectLoop(Delay(int timeInMs), Reverb(St
return timeInMs == roomSize;
}
return false;
}
1
2
3
4
5
6
Var and any patterns
Var and any patterns
// Pre-Java 10
Guitar telecaster = new Guitar("Fender Telecaster Baritone Blacktop", G
// Java 10
var telecaster = new Guitar("Fender Telecaster Baritone Blacktop", Gui
1
2
3
4
5
https://openjdk.java.net/jeps/286
Var and any patterns
Var and any patterns
static boolean isDelayTimeEqualToReverbRoomSize(EffectLoop effectLoop)
if (effectLoop instanceof EffectLoop(Delay(int timeInMs), Reverb(St
return timeInMs == roomSize;
}
return false;
}
1
2
3
4
5
6
Var and any patterns
Var and any patterns
if (effectLoop instanceof EffectLoop(Delay(var timeInMs), Reverb(v
static boolean isDelayTimeEqualToReverbRoomSize(EffectLoop effectLoop)
1
2
return timeInMs == roomSize;
3
}
4
return false;
5
}
6
http://gph.is/2lFlHIK
Var and any patterns
Var and any patterns
static boolean isDelayTimeEqualToReverbRoomSize(EffectLoop effectLoop)
if (effectLoop instanceof EffectLoop(Delay(var timeInMs), Reverb(_
return timeInMs == roomSize;
}
return false;
}
1
2
3
4
5
6
Optimization
Optimization
static String apply(Effect effect) {
return switch(effect) {
case Delay(int timeInMs) -> String.format("Delay active of %d
case Reverb(String name, int roomSize) -> String.format("Reve
case Overdrive(int gain) -> String.format("Overdrive active w
case Tremolo(int depth, int rate) -> String.format("Tremolo ac
case Tuner(int pitchInHz) -> String.format("Tuner active with
case EffectLoop(var effects) -> effects.stream().map(Effect::
default -> String.format("Unknown effect active: %s.", effect
};
}
1
2
3
4
5
6
7
8
9
10
11
Optimization
Optimization
case EffectLoop(var effects) -> effects.stream().map(Effect::ap
static String apply(Effect effect) {
1
return switch(effect) {
2
// ...
3
4
default -> String.format("Unknown effect active: %s.", effect)
5
};
6
}
7
Optimization
Optimization
case EffectLoop(Tuner(int pitchInHz), _) -> String.format("The
case EffectLoop(var effects) -> effects.stream().map(Effect::ap
static String apply(Effect effect) {
1
return switch(effect) {
2
// ...
3
4
5
default -> String.format("Unknown effect active: %s.", effect)
6
};
7
}
8
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
Feature Status
Feature Status
Java
version
Feature status JEP
n/a Exploratory
document
Pattern Matching
for Java
https://cr.openjdk.java.net/~briangoetz/amber/pattern-match.html
Pattern Matching Plays
Pattern Matching Plays
Nice With
Nice 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
Completeness on pattern switch
Completeness on pattern switch
expressions
expressions
static String apply(Object object) {
return switch(object) {
case Effect e -> e.apply();
case String s -> String.format("Tried to apply a String: %s",
case Number n -> String.format("Tried to apply a Number: %d",
};
}
1
2
3
4
5
6
7
Completeness on pattern switch
Completeness on pattern switch
expressions
expressions
return switch(object) { // Won't compile - incomplete!
static String apply(Object object) {
1
2
case Effect e -> e.apply();
3
case String s -> String.format("Tried to apply a String: %s",
4
case Number n -> String.format("Tried to apply a Number: %d",
5
};
6
}
7
Completeness on pattern switch
Completeness on pattern switch
expressions
expressions
default -> String.format("Tried to apply an Object: %s",
static String apply(Object object) {
1
return switch(object) {
2
case Effect e -> e.apply();
3
case String s -> String.format("Tried to apply a String: %s",
4
case Number n -> String.format("Tried to apply a Number: %d",
5
6
};
7
}
8
Demo
Demo
Make Effect a sealed type
https://pxhere.com/en/photo/1458897
Sealed types yield
Sealed types yield
completeness
completeness
static String apply(Effect effect) {
return switch(effect) {
case Delay(int timeInMs) -> String.format("Delay active of %d
case Reverb(String name, int roomSize) -> String.format("Reve
case Overdrive(int gain) -> String.format("Overdrive active w
case Tremolo(int depth, int rate) -> String.format("Tremolo ac
case Tuner(int pitchInHz) -> String.format("Tuner active with
case EffectLoop(Tuner(int pitchInHz), _) -> String.format("The
case EffectLoop(var effects) -> effects.stream().map(Effect::
default -> String.format("Unknown effect active: %s.", effect
};
}
1
2
3
4
5
6
7
8
9
10
11
12
Sealed types yield
Sealed types yield
completeness
completeness
static String apply(Effect effect) {
return switch(effect) {
case Delay(int timeInMs) -> String.format("Delay active of %d
case Reverb(String name, int roomSize) -> String.format("Reve
case Overdrive(int gain) -> String.format("Overdrive active w
case Tremolo(int depth, int rate) -> String.format("Tremolo ac
case Tuner(int pitchInHz) -> String.format("Tuner active with
case EffectLoop(Tuner(int pitchInHz), _) -> String.format("The
case EffectLoop(var effects) -> effects.stream().map(Effect::
};
}
1
2
3
4
5
6
7
8
9
10
11
https://cr.openjdk.java.net/~briangoetz/amber/pattern-match.html
Demo
Demo
Convert an implementing class to a record
Acquire constructor, accessor methods etc.
https://pxhere.com/en/photo/1458897
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
Record patterns
Record patterns
record Amplifier(String name, EffectLoop stockEffects, EffectLoop auxE
record EffectLoop(Delay delay, Reverb reverb) { }
1
2
static String switchOn(Amplifier amplifier) {
return switch(effectLoop) {
// ...
case Amplifier(var name, EffectLoop(Delay(int timeInMs), Reverb
// ...
}
}
1
2
3
4
5
6
7
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 contain
case EffectLoop(var name, var volume, var effect) -> "Effect lo
case EffectLoop(var name, var volume, var effect, ...) -> "Eff
case EffectLoop(var name, var volume, var effect1, var effect2
case EffectLoop(var name, var volume, var effect1, var effect2
}
}
1
2
3
4
5
6
7
8
9
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
Feature Status
Feature Status
Completeness
Completeness
Java version Feature status JEP
17 Preview JEP 406
https://openjdk.java.net/jeps/406
Feature Status
Feature Status
Record & Array Patterns
Record & Array Patterns
Java version Feature status JEP
18 Preview JEP 405
A Better
A Better
A Better
A Better
A Better
Serialization
Serialization
Serialization
Serialization
Serialization
?
?
?
?
?
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/
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
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
Serialization
Serialization
public class EffectLoop implements Effect {
private String name;
private Set<Effect> effects;
public EffectLoop(String name) {
this.name = name;
this.effects = new HashSet<>();
}
}
1
2
3
4
5
6
7
8
9
Serialization
Serialization
public pattern EffectLoop(String name, Effect[] effects) {
name = this.name;
effects = this.effects.toArray();
}
public class EffectLoop implements Effect {
1
private String name;
2
private Set<Effect> effects;
3
4
public EffectLoop(String name) {
5
this.name = name;
6
this.effects = new HashSet<>();
7
}
8
9
10
11
12
13
}
14
Serialization
Serialization
public static Effectloop deserialize(String name, Effect[] effect
EffectLoop effectLoop = new EffectLoop(name);
for (Effect effect : effects) {
this.effects.add(effect);
}
return effectLoop;
public class EffectLoop implements Effect {
1
private String name;
2
private Set<Effect> effects;
3
4
public EffectLoop(String name) {
5
this.name = name;
6
this.effects = new HashSet<>();
7
}
8
9
10
11
12
13
14
15
}
16
Serialization
Serialization
public class EffectLoop implements Effect {
private String name;
private Set<Effect> effects;
public EffectLoop(String name) {
this.name = name;
this.effects = new HashSet<>();
}
@Deserializer
public static EffectLoop deserialize(String name, Effect[] effect
EffectLoop effectLoop = new EffectLoop(name);
for (Effect effect : effects) {
this.effects.add(effect);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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
Future
Future
Future
Future
Future
Expansions
Expansions
Expansions
Expansions
Expansions
https://pxhere.com/en/photo/752901
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/
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
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
// do something with name & roomSize
6
Other ideas
Other ideas
Deconstruction patterns for all classes
Enhanced array patterns

String[] { [8] -> var eighthElement, [9] -> var ninthElement}
AND patterns
Patterns in catch clauses
Collection patterns
https://mail.openjdk.java.net/pipermail/amber-spec-experts/2021-January/002758.html
Wrap-up
Wrap-up
Wrap-up
Wrap-up
Wrap-up
https://pxhere.com/en/photo/752901
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 (and more
similar to) constructing them.
holds the potential to simplify and streamline much
of the code we write today.
Major Feature
Major Feature
Major Feature
Major Feature
Major Feature
#jLoveConf #PatternMatching @hannotify
Thank you! ☺️
Thank you! ☺️
bit.do/jlove-pattern-matching
github.com/hannotify/pattern-
matching-music-store
hanno.codes
@hannotify

Weitere ähnliche Inhalte

Was ist angesagt?

Introduction to ad-3.4, an automatic differentiation library in Haskell
Introduction to ad-3.4, an automatic differentiation library in HaskellIntroduction to ad-3.4, an automatic differentiation library in Haskell
Introduction to ad-3.4, an automatic differentiation library in Haskellnebuta
 
Concurrency in go
Concurrency in goConcurrency in go
Concurrency in goborderj
 
Laziness, trampolines, monoids and other functional amenities: this is not yo...
Laziness, trampolines, monoids and other functional amenities: this is not yo...Laziness, trampolines, monoids and other functional amenities: this is not yo...
Laziness, trampolines, monoids and other functional amenities: this is not yo...Mario Fusco
 
Python Functions (PyAtl Beginners Night)
Python Functions (PyAtl Beginners Night)Python Functions (PyAtl Beginners Night)
Python Functions (PyAtl Beginners Night)Rick Copeland
 
Grammatical Optimization
Grammatical OptimizationGrammatical Optimization
Grammatical Optimizationadil raja
 
Load-time Hacking using LD_PRELOAD
Load-time Hacking using LD_PRELOADLoad-time Hacking using LD_PRELOAD
Load-time Hacking using LD_PRELOADDharmalingam Ganesan
 
Functional programming in C++ LambdaNsk
Functional programming in C++ LambdaNskFunctional programming in C++ LambdaNsk
Functional programming in C++ LambdaNskAlexander Granin
 
'Getting' Clojure - '(parentheses are just hugs for your code)
'Getting' Clojure - '(parentheses are just hugs for your code)'Getting' Clojure - '(parentheses are just hugs for your code)
'Getting' Clojure - '(parentheses are just hugs for your code)Gary Trakhman
 
2013-02-21 - .NET UG Rhein-Neckar: JavaScript Best Practices
2013-02-21 - .NET UG Rhein-Neckar: JavaScript Best Practices2013-02-21 - .NET UG Rhein-Neckar: JavaScript Best Practices
2013-02-21 - .NET UG Rhein-Neckar: JavaScript Best PracticesJohannes Hoppe
 
Functions in python
Functions in pythonFunctions in python
Functions in pythonIlian Iliev
 
The Ring programming language version 1.3 book - Part 57 of 88
The Ring programming language version 1.3 book - Part 57 of 88The Ring programming language version 1.3 book - Part 57 of 88
The Ring programming language version 1.3 book - Part 57 of 88Mahmoud Samir Fayed
 
SAE: Structured Aspect Extraction
SAE: Structured Aspect ExtractionSAE: Structured Aspect Extraction
SAE: Structured Aspect ExtractionGiorgio Orsi
 
[ShaderX5] 8 1 Postprocessing Effects In Design
[ShaderX5] 8 1 Postprocessing Effects In Design[ShaderX5] 8 1 Postprocessing Effects In Design
[ShaderX5] 8 1 Postprocessing Effects In Design종빈 오
 
The Ring programming language version 1.5.2 book - Part 72 of 181
The Ring programming language version 1.5.2 book - Part 72 of 181The Ring programming language version 1.5.2 book - Part 72 of 181
The Ring programming language version 1.5.2 book - Part 72 of 181Mahmoud Samir Fayed
 
Let's make a contract: the art of designing a Java API
Let's make a contract: the art of designing a Java APILet's make a contract: the art of designing a Java API
Let's make a contract: the art of designing a Java APIMario Fusco
 

Was ist angesagt? (20)

Slicing
SlicingSlicing
Slicing
 
Introduction to ad-3.4, an automatic differentiation library in Haskell
Introduction to ad-3.4, an automatic differentiation library in HaskellIntroduction to ad-3.4, an automatic differentiation library in Haskell
Introduction to ad-3.4, an automatic differentiation library in Haskell
 
Concurrency in go
Concurrency in goConcurrency in go
Concurrency in go
 
Laziness, trampolines, monoids and other functional amenities: this is not yo...
Laziness, trampolines, monoids and other functional amenities: this is not yo...Laziness, trampolines, monoids and other functional amenities: this is not yo...
Laziness, trampolines, monoids and other functional amenities: this is not yo...
 
Python Functions (PyAtl Beginners Night)
Python Functions (PyAtl Beginners Night)Python Functions (PyAtl Beginners Night)
Python Functions (PyAtl Beginners Night)
 
Grammatical Optimization
Grammatical OptimizationGrammatical Optimization
Grammatical Optimization
 
Load-time Hacking using LD_PRELOAD
Load-time Hacking using LD_PRELOADLoad-time Hacking using LD_PRELOAD
Load-time Hacking using LD_PRELOAD
 
Functional programming in C++ LambdaNsk
Functional programming in C++ LambdaNskFunctional programming in C++ LambdaNsk
Functional programming in C++ LambdaNsk
 
'Getting' Clojure - '(parentheses are just hugs for your code)
'Getting' Clojure - '(parentheses are just hugs for your code)'Getting' Clojure - '(parentheses are just hugs for your code)
'Getting' Clojure - '(parentheses are just hugs for your code)
 
Programming Homework Help
Programming Homework Help Programming Homework Help
Programming Homework Help
 
2013-02-21 - .NET UG Rhein-Neckar: JavaScript Best Practices
2013-02-21 - .NET UG Rhein-Neckar: JavaScript Best Practices2013-02-21 - .NET UG Rhein-Neckar: JavaScript Best Practices
2013-02-21 - .NET UG Rhein-Neckar: JavaScript Best Practices
 
Input and Output
Input and OutputInput and Output
Input and Output
 
Functions in python
Functions in pythonFunctions in python
Functions in python
 
The Ring programming language version 1.3 book - Part 57 of 88
The Ring programming language version 1.3 book - Part 57 of 88The Ring programming language version 1.3 book - Part 57 of 88
The Ring programming language version 1.3 book - Part 57 of 88
 
Go testdeep
Go testdeepGo testdeep
Go testdeep
 
SAE: Structured Aspect Extraction
SAE: Structured Aspect ExtractionSAE: Structured Aspect Extraction
SAE: Structured Aspect Extraction
 
[ShaderX5] 8 1 Postprocessing Effects In Design
[ShaderX5] 8 1 Postprocessing Effects In Design[ShaderX5] 8 1 Postprocessing Effects In Design
[ShaderX5] 8 1 Postprocessing Effects In Design
 
OpenMP
OpenMPOpenMP
OpenMP
 
The Ring programming language version 1.5.2 book - Part 72 of 181
The Ring programming language version 1.5.2 book - Part 72 of 181The Ring programming language version 1.5.2 book - Part 72 of 181
The Ring programming language version 1.5.2 book - Part 72 of 181
 
Let's make a contract: the art of designing a Java API
Let's make a contract: the art of designing a Java APILet's make a contract: the art of designing a Java API
Let's make a contract: the art of designing a Java API
 

Ähnlich wie Pattern Matching: Small Enhancement or Major Feature? (talk from jLove 2021)

Pattern Matching: Small Enhancement or Major Feature?
Pattern Matching: Small Enhancement or Major Feature?Pattern Matching: Small Enhancement or Major Feature?
Pattern Matching: Small Enhancement or Major Feature?🎤 Hanno Embregts 🎸
 
Pattern Matching - Small Enhancement or Major Feature? from Developer Week 202
Pattern Matching - Small Enhancement or Major Feature? from Developer Week 202Pattern Matching - Small Enhancement or Major Feature? from Developer Week 202
Pattern Matching - Small Enhancement or Major Feature? from Developer Week 202🎤 Hanno Embregts 🎸
 
AST Transformations at JFokus
AST Transformations at JFokusAST Transformations at JFokus
AST Transformations at JFokusHamletDRC
 
Ast transformations
Ast transformationsAst transformations
Ast transformationsHamletDRC
 
JavaScript - Like a Box of Chocolates
JavaScript - Like a Box of ChocolatesJavaScript - Like a Box of Chocolates
JavaScript - Like a Box of ChocolatesRobert Nyman
 
Android & Kotlin - The code awakens #03
Android & Kotlin - The code awakens #03Android & Kotlin - The code awakens #03
Android & Kotlin - The code awakens #03Omar Miatello
 
Logic Equations Resolver J Script
Logic Equations Resolver   J ScriptLogic Equations Resolver   J Script
Logic Equations Resolver J ScriptRoman Agaev
 
Go ahead, make my day
Go ahead, make my dayGo ahead, make my day
Go ahead, make my dayTor Ivry
 
Naïveté vs. Experience
Naïveté vs. ExperienceNaïveté vs. Experience
Naïveté vs. ExperienceMike Fogus
 
What's new in Perl 5.10?
What's new in Perl 5.10?What's new in Perl 5.10?
What's new in Perl 5.10?acme
 
Thirteen ways of looking at a turtle
Thirteen ways of looking at a turtleThirteen ways of looking at a turtle
Thirteen ways of looking at a turtleScott Wlaschin
 
Throttle and Debounce Patterns in Web Apps
Throttle and Debounce Patterns in Web AppsThrottle and Debounce Patterns in Web Apps
Throttle and Debounce Patterns in Web AppsAlmir Filho
 
名古屋SGGAE/J勉強会 Grails、Gaelykでハンズオン
名古屋SGGAE/J勉強会 Grails、Gaelykでハンズオン名古屋SGGAE/J勉強会 Grails、Gaelykでハンズオン
名古屋SGGAE/J勉強会 Grails、GaelykでハンズオンTsuyoshi Yamamoto
 
How I learned to stop fucking and love MarionetteJS
How I learned to stop fucking and love MarionetteJSHow I learned to stop fucking and love MarionetteJS
How I learned to stop fucking and love MarionetteJSKamol Treewatchararat
 
JSConf: All You Can Leet
JSConf: All You Can LeetJSConf: All You Can Leet
JSConf: All You Can Leetjohndaviddalton
 
Functional Programming In Java
Functional Programming In JavaFunctional Programming In Java
Functional Programming In JavaAndrei Solntsev
 
How to not write a boring test in Golang
How to not write a boring test in GolangHow to not write a boring test in Golang
How to not write a boring test in GolangDan Tran
 
JavaScript - Like a Box of Chocolates - jsDay
JavaScript - Like a Box of Chocolates - jsDayJavaScript - Like a Box of Chocolates - jsDay
JavaScript - Like a Box of Chocolates - jsDayRobert Nyman
 
Introduction to Swift programming language.
Introduction to Swift programming language.Introduction to Swift programming language.
Introduction to Swift programming language.Icalia Labs
 

Ähnlich wie Pattern Matching: Small Enhancement or Major Feature? (talk from jLove 2021) (20)

Pattern Matching: Small Enhancement or Major Feature?
Pattern Matching: Small Enhancement or Major Feature?Pattern Matching: Small Enhancement or Major Feature?
Pattern Matching: Small Enhancement or Major Feature?
 
Pattern Matching - Small Enhancement or Major Feature? from Developer Week 202
Pattern Matching - Small Enhancement or Major Feature? from Developer Week 202Pattern Matching - Small Enhancement or Major Feature? from Developer Week 202
Pattern Matching - Small Enhancement or Major Feature? from Developer Week 202
 
AST Transformations at JFokus
AST Transformations at JFokusAST Transformations at JFokus
AST Transformations at JFokus
 
Ast transformations
Ast transformationsAst transformations
Ast transformations
 
PSOGlobalSearching
PSOGlobalSearchingPSOGlobalSearching
PSOGlobalSearching
 
JavaScript - Like a Box of Chocolates
JavaScript - Like a Box of ChocolatesJavaScript - Like a Box of Chocolates
JavaScript - Like a Box of Chocolates
 
Android & Kotlin - The code awakens #03
Android & Kotlin - The code awakens #03Android & Kotlin - The code awakens #03
Android & Kotlin - The code awakens #03
 
Logic Equations Resolver J Script
Logic Equations Resolver   J ScriptLogic Equations Resolver   J Script
Logic Equations Resolver J Script
 
Go ahead, make my day
Go ahead, make my dayGo ahead, make my day
Go ahead, make my day
 
Naïveté vs. Experience
Naïveté vs. ExperienceNaïveté vs. Experience
Naïveté vs. Experience
 
What's new in Perl 5.10?
What's new in Perl 5.10?What's new in Perl 5.10?
What's new in Perl 5.10?
 
Thirteen ways of looking at a turtle
Thirteen ways of looking at a turtleThirteen ways of looking at a turtle
Thirteen ways of looking at a turtle
 
Throttle and Debounce Patterns in Web Apps
Throttle and Debounce Patterns in Web AppsThrottle and Debounce Patterns in Web Apps
Throttle and Debounce Patterns in Web Apps
 
名古屋SGGAE/J勉強会 Grails、Gaelykでハンズオン
名古屋SGGAE/J勉強会 Grails、Gaelykでハンズオン名古屋SGGAE/J勉強会 Grails、Gaelykでハンズオン
名古屋SGGAE/J勉強会 Grails、Gaelykでハンズオン
 
How I learned to stop fucking and love MarionetteJS
How I learned to stop fucking and love MarionetteJSHow I learned to stop fucking and love MarionetteJS
How I learned to stop fucking and love MarionetteJS
 
JSConf: All You Can Leet
JSConf: All You Can LeetJSConf: All You Can Leet
JSConf: All You Can Leet
 
Functional Programming In Java
Functional Programming In JavaFunctional Programming In Java
Functional Programming In Java
 
How to not write a boring test in Golang
How to not write a boring test in GolangHow to not write a boring test in Golang
How to not write a boring test in Golang
 
JavaScript - Like a Box of Chocolates - jsDay
JavaScript - Like a Box of Chocolates - jsDayJavaScript - Like a Box of Chocolates - jsDay
JavaScript - Like a Box of Chocolates - jsDay
 
Introduction to Swift programming language.
Introduction to Swift programming language.Introduction to Swift programming language.
Introduction to Swift programming language.
 

Mehr von 🎤 Hanno Embregts 🎸

"Will Git Be Around Forever? A List of Possible Successors" from Devoxx 2022
"Will Git Be Around Forever? A List of Possible Successors" from Devoxx 2022"Will Git Be Around Forever? A List of Possible Successors" from Devoxx 2022
"Will Git Be Around Forever? A List of Possible Successors" from Devoxx 2022🎤 Hanno Embregts 🎸
 
"Will Git Be Around Forever? A List of Possible Successors" from FrontMania 2022
"Will Git Be Around Forever? A List of Possible Successors" from FrontMania 2022"Will Git Be Around Forever? A List of Possible Successors" from FrontMania 2022
"Will Git Be Around Forever? A List of Possible Successors" from FrontMania 2022🎤 Hanno Embregts 🎸
 
JCON 2021 talk - "Wil Git Be Around Forever? A List of Possible Successors"
JCON 2021 talk - "Wil Git Be Around Forever? A List of Possible Successors"JCON 2021 talk - "Wil Git Be Around Forever? A List of Possible Successors"
JCON 2021 talk - "Wil Git Be Around Forever? A List of Possible Successors"🎤 Hanno Embregts 🎸
 
"Will Git Be Around Forever? A List of Possible Successors" at UtrechtJUG
"Will Git Be Around Forever? A List of Possible Successors" at UtrechtJUG"Will Git Be Around Forever? A List of Possible Successors" at UtrechtJUG
"Will Git Be Around Forever? A List of Possible Successors" at UtrechtJUG🎤 Hanno Embregts 🎸
 
Entering the Fourth Dimension of OCR with Tesseract
Entering the Fourth Dimension of OCR with TesseractEntering the Fourth Dimension of OCR with Tesseract
Entering the Fourth Dimension of OCR with Tesseract🎤 Hanno Embregts 🎸
 
The Soft Side of Software Development / Devoxx 2019
The Soft Side of Software Development / Devoxx 2019The Soft Side of Software Development / Devoxx 2019
The Soft Side of Software Development / Devoxx 2019🎤 Hanno Embregts 🎸
 
Beware of Survivorship Bias! (conference talk at J-Fall 2019)
Beware of Survivorship Bias! (conference talk at J-Fall 2019)Beware of Survivorship Bias! (conference talk at J-Fall 2019)
Beware of Survivorship Bias! (conference talk at J-Fall 2019)🎤 Hanno Embregts 🎸
 
Will Git Be Around Forever? A List of Possible Successors
Will Git Be Around Forever? A List of Possible SuccessorsWill Git Be Around Forever? A List of Possible Successors
Will Git Be Around Forever? A List of Possible Successors🎤 Hanno Embregts 🎸
 
Entering the Fourth Dimension of OCR with Tesseract - Talk from Voxxed Days B...
Entering the Fourth Dimension of OCR with Tesseract - Talk from Voxxed Days B...Entering the Fourth Dimension of OCR with Tesseract - Talk from Voxxed Days B...
Entering the Fourth Dimension of OCR with Tesseract - Talk from Voxxed Days B...🎤 Hanno Embregts 🎸
 
QWERTY or DVORAK? Debunking the Keyboard Layout Myths -- from GeeCON 2018
QWERTY or DVORAK? Debunking the Keyboard Layout Myths -- from GeeCON 2018QWERTY or DVORAK? Debunking the Keyboard Layout Myths -- from GeeCON 2018
QWERTY or DVORAK? Debunking the Keyboard Layout Myths -- from GeeCON 2018🎤 Hanno Embregts 🎸
 
Building a Spring Boot 2 Application - Ask the Audience! (from Voxxed Days Vi...
Building a Spring Boot 2 Application - Ask the Audience! (from Voxxed Days Vi...Building a Spring Boot 2 Application - Ask the Audience! (from Voxxed Days Vi...
Building a Spring Boot 2 Application - Ask the Audience! (from Voxxed Days Vi...🎤 Hanno Embregts 🎸
 
Building a Spring Boot Application - Ask the Audience! (from JVMCon 2018)
Building a Spring Boot Application - Ask the Audience! (from JVMCon 2018)Building a Spring Boot Application - Ask the Audience! (from JVMCon 2018)
Building a Spring Boot Application - Ask the Audience! (from JVMCon 2018)🎤 Hanno Embregts 🎸
 
Building a Spring Boot Application - Ask the Audience!
Building a Spring Boot Application - Ask the Audience!Building a Spring Boot Application - Ask the Audience!
Building a Spring Boot Application - Ask the Audience!🎤 Hanno Embregts 🎸
 
QWERTY or DVORAK? Debunking the Keyboard Layout Myths
QWERTY or DVORAK? Debunking the Keyboard Layout MythsQWERTY or DVORAK? Debunking the Keyboard Layout Myths
QWERTY or DVORAK? Debunking the Keyboard Layout Myths🎤 Hanno Embregts 🎸
 
Building a Spring Boot Application - Ask the Audience! (from JavaLand 2017)
Building a Spring Boot Application - Ask the Audience!  (from JavaLand 2017)Building a Spring Boot Application - Ask the Audience!  (from JavaLand 2017)
Building a Spring Boot Application - Ask the Audience! (from JavaLand 2017)🎤 Hanno Embregts 🎸
 
Migrating 25K lines of Ant scripting to Gradle
Migrating 25K lines of Ant scripting to GradleMigrating 25K lines of Ant scripting to Gradle
Migrating 25K lines of Ant scripting to Gradle🎤 Hanno Embregts 🎸
 

Mehr von 🎤 Hanno Embregts 🎸 (16)

"Will Git Be Around Forever? A List of Possible Successors" from Devoxx 2022
"Will Git Be Around Forever? A List of Possible Successors" from Devoxx 2022"Will Git Be Around Forever? A List of Possible Successors" from Devoxx 2022
"Will Git Be Around Forever? A List of Possible Successors" from Devoxx 2022
 
"Will Git Be Around Forever? A List of Possible Successors" from FrontMania 2022
"Will Git Be Around Forever? A List of Possible Successors" from FrontMania 2022"Will Git Be Around Forever? A List of Possible Successors" from FrontMania 2022
"Will Git Be Around Forever? A List of Possible Successors" from FrontMania 2022
 
JCON 2021 talk - "Wil Git Be Around Forever? A List of Possible Successors"
JCON 2021 talk - "Wil Git Be Around Forever? A List of Possible Successors"JCON 2021 talk - "Wil Git Be Around Forever? A List of Possible Successors"
JCON 2021 talk - "Wil Git Be Around Forever? A List of Possible Successors"
 
"Will Git Be Around Forever? A List of Possible Successors" at UtrechtJUG
"Will Git Be Around Forever? A List of Possible Successors" at UtrechtJUG"Will Git Be Around Forever? A List of Possible Successors" at UtrechtJUG
"Will Git Be Around Forever? A List of Possible Successors" at UtrechtJUG
 
Entering the Fourth Dimension of OCR with Tesseract
Entering the Fourth Dimension of OCR with TesseractEntering the Fourth Dimension of OCR with Tesseract
Entering the Fourth Dimension of OCR with Tesseract
 
The Soft Side of Software Development / Devoxx 2019
The Soft Side of Software Development / Devoxx 2019The Soft Side of Software Development / Devoxx 2019
The Soft Side of Software Development / Devoxx 2019
 
Beware of Survivorship Bias! (conference talk at J-Fall 2019)
Beware of Survivorship Bias! (conference talk at J-Fall 2019)Beware of Survivorship Bias! (conference talk at J-Fall 2019)
Beware of Survivorship Bias! (conference talk at J-Fall 2019)
 
Will Git Be Around Forever? A List of Possible Successors
Will Git Be Around Forever? A List of Possible SuccessorsWill Git Be Around Forever? A List of Possible Successors
Will Git Be Around Forever? A List of Possible Successors
 
Entering the Fourth Dimension of OCR with Tesseract - Talk from Voxxed Days B...
Entering the Fourth Dimension of OCR with Tesseract - Talk from Voxxed Days B...Entering the Fourth Dimension of OCR with Tesseract - Talk from Voxxed Days B...
Entering the Fourth Dimension of OCR with Tesseract - Talk from Voxxed Days B...
 
QWERTY or DVORAK? Debunking the Keyboard Layout Myths -- from GeeCON 2018
QWERTY or DVORAK? Debunking the Keyboard Layout Myths -- from GeeCON 2018QWERTY or DVORAK? Debunking the Keyboard Layout Myths -- from GeeCON 2018
QWERTY or DVORAK? Debunking the Keyboard Layout Myths -- from GeeCON 2018
 
Building a Spring Boot 2 Application - Ask the Audience! (from Voxxed Days Vi...
Building a Spring Boot 2 Application - Ask the Audience! (from Voxxed Days Vi...Building a Spring Boot 2 Application - Ask the Audience! (from Voxxed Days Vi...
Building a Spring Boot 2 Application - Ask the Audience! (from Voxxed Days Vi...
 
Building a Spring Boot Application - Ask the Audience! (from JVMCon 2018)
Building a Spring Boot Application - Ask the Audience! (from JVMCon 2018)Building a Spring Boot Application - Ask the Audience! (from JVMCon 2018)
Building a Spring Boot Application - Ask the Audience! (from JVMCon 2018)
 
Building a Spring Boot Application - Ask the Audience!
Building a Spring Boot Application - Ask the Audience!Building a Spring Boot Application - Ask the Audience!
Building a Spring Boot Application - Ask the Audience!
 
QWERTY or DVORAK? Debunking the Keyboard Layout Myths
QWERTY or DVORAK? Debunking the Keyboard Layout MythsQWERTY or DVORAK? Debunking the Keyboard Layout Myths
QWERTY or DVORAK? Debunking the Keyboard Layout Myths
 
Building a Spring Boot Application - Ask the Audience! (from JavaLand 2017)
Building a Spring Boot Application - Ask the Audience!  (from JavaLand 2017)Building a Spring Boot Application - Ask the Audience!  (from JavaLand 2017)
Building a Spring Boot Application - Ask the Audience! (from JavaLand 2017)
 
Migrating 25K lines of Ant scripting to Gradle
Migrating 25K lines of Ant scripting to GradleMigrating 25K lines of Ant scripting to Gradle
Migrating 25K lines of Ant scripting to Gradle
 

Kürzlich hochgeladen

Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...
Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...
Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...confluent
 
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company OdishaBalasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odishasmiwainfosol
 
How to submit a standout Adobe Champion Application
How to submit a standout Adobe Champion ApplicationHow to submit a standout Adobe Champion Application
How to submit a standout Adobe Champion ApplicationBradBedford3
 
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...Cizo Technology Services
 
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...Angel Borroy López
 
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte GermanySuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte GermanyChristoph Pohl
 
20240415 [Container Plumbing Days] Usernetes Gen2 - Kubernetes in Rootless Do...
20240415 [Container Plumbing Days] Usernetes Gen2 - Kubernetes in Rootless Do...20240415 [Container Plumbing Days] Usernetes Gen2 - Kubernetes in Rootless Do...
20240415 [Container Plumbing Days] Usernetes Gen2 - Kubernetes in Rootless Do...Akihiro Suda
 
Implementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureImplementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureDinusha Kumarasiri
 
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...OnePlan Solutions
 
Folding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesFolding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesPhilip Schwarz
 
Powering Real-Time Decisions with Continuous Data Streams
Powering Real-Time Decisions with Continuous Data StreamsPowering Real-Time Decisions with Continuous Data Streams
Powering Real-Time Decisions with Continuous Data StreamsSafe Software
 
React Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaReact Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaHanief Utama
 
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...Matt Ray
 
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024StefanoLambiase
 
SensoDat: Simulation-based Sensor Dataset of Self-driving Cars
SensoDat: Simulation-based Sensor Dataset of Self-driving CarsSensoDat: Simulation-based Sensor Dataset of Self-driving Cars
SensoDat: Simulation-based Sensor Dataset of Self-driving CarsChristian Birchler
 
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)jennyeacort
 
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...OnePlan Solutions
 
Ahmed Motair CV April 2024 (Senior SW Developer)
Ahmed Motair CV April 2024 (Senior SW Developer)Ahmed Motair CV April 2024 (Senior SW Developer)
Ahmed Motair CV April 2024 (Senior SW Developer)Ahmed Mater
 
Salesforce Implementation Services PPT By ABSYZ
Salesforce Implementation Services PPT By ABSYZSalesforce Implementation Services PPT By ABSYZ
Salesforce Implementation Services PPT By ABSYZABSYZ Inc
 

Kürzlich hochgeladen (20)

Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...
Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...
Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...
 
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company OdishaBalasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
 
How to submit a standout Adobe Champion Application
How to submit a standout Adobe Champion ApplicationHow to submit a standout Adobe Champion Application
How to submit a standout Adobe Champion Application
 
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
 
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
 
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort ServiceHot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
 
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte GermanySuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
 
20240415 [Container Plumbing Days] Usernetes Gen2 - Kubernetes in Rootless Do...
20240415 [Container Plumbing Days] Usernetes Gen2 - Kubernetes in Rootless Do...20240415 [Container Plumbing Days] Usernetes Gen2 - Kubernetes in Rootless Do...
20240415 [Container Plumbing Days] Usernetes Gen2 - Kubernetes in Rootless Do...
 
Implementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureImplementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with Azure
 
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
 
Folding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesFolding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a series
 
Powering Real-Time Decisions with Continuous Data Streams
Powering Real-Time Decisions with Continuous Data StreamsPowering Real-Time Decisions with Continuous Data Streams
Powering Real-Time Decisions with Continuous Data Streams
 
React Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaReact Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief Utama
 
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
 
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
 
SensoDat: Simulation-based Sensor Dataset of Self-driving Cars
SensoDat: Simulation-based Sensor Dataset of Self-driving CarsSensoDat: Simulation-based Sensor Dataset of Self-driving Cars
SensoDat: Simulation-based Sensor Dataset of Self-driving Cars
 
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
 
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
 
Ahmed Motair CV April 2024 (Senior SW Developer)
Ahmed Motair CV April 2024 (Senior SW Developer)Ahmed Motair CV April 2024 (Senior SW Developer)
Ahmed Motair CV April 2024 (Senior SW Developer)
 
Salesforce Implementation Services PPT By ABSYZ
Salesforce Implementation Services PPT By ABSYZSalesforce Implementation Services PPT By ABSYZ
Salesforce Implementation Services PPT By ABSYZ
 

Pattern Matching: Small Enhancement or Major Feature? (talk from jLove 2021)

  • 2.
  • 3. Small Enhancement Small Enhancement Small Enhancement Small Enhancement Small Enhancement https://gph.is/g/ZPJNoPQ
  • 4. Major Feature Major Feature Major Feature Major Feature Major Feature https://thumbs.gfycat.com/DefiantElasticGadwall.webp
  • 5. 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
  • 7. Instanceof-and-cast Instanceof-and-cast if (product instanceof Guitar) { Guitar lesPaul = (Guitar) product; // use lesPaul } 1 2 3 4 5
  • 8. 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
  • 9. 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
  • 10. 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
  • 11. 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
  • 12. Improve the situation Improve the situation if (product instanceof Guitar lesPaul) { // use lesPaul } 1 2 3
  • 13. 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/
  • 14. Declaring 'in the Declaring 'in the middle' middle' if (product instanceof Guitar lesPaul) { // use lesPaul } 1 2 3
  • 15. Scoping Scoping 'Regular' local variable ('block scoping') 'Regular' local variable ('block scoping') The block in which it is declared. void playTunedGuitar() { Guitar lesPaul = new Guitar("Les Paul"); if (!lesPaul.isInTune()) { Guitar fenderStrat = new Guitar("Fender Stratocaster"); fenderStrat.play(); } } 1 2 3 4 5 6 7 8
  • 16. Scoping Scoping 'Regular' local variable ('block scoping') 'Regular' local variable ('block scoping') The block in which it is declared. void playTunedGuitar() { Guitar lesPaul = new Guitar("Les Paul"); if (!lesPaul.isInTune()) { Guitar fenderStrat = new Guitar("Fender Stratocaster"); fenderStrat.play(); // fenderStrat is in scope } // fenderStrat is not in scope } 1 2 3 4 5 6 7 8 9 10
  • 17. 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) { // can use lesPaul here } else { // can't use lesPaul here } 1 2 3 4 5
  • 18. Scoping Scoping Pattern binding variable ('flow scoping') Pattern binding variable ('flow scoping') The set of places where it would definitely be assigned. boolean isTunedGuitar(Object product) { if (!(product instanceof Guitar lesPaul)) { return false; } // This code is only reachable if 'product' is // a Guitar, so 'lesPaul' is in scope. return lesPaul.isInTune(); } 1 2 3 4 5 6 7 8 9
  • 19.
  • 20. Scoping Scoping Pattern binding variable ('flow scoping') Pattern binding variable ('flow scoping') The set of places where it would definitely be assigned. void test(Effect effect) { if (effect instanceof Reverb stockEffect) stockEffect.setRoomSize(25); else if (effect instanceof Delay stockEffect) stockEffect.setTimeInMs(200); } 1 2 3 4 5 6
  • 21.
  • 22. Demo Demo Simplify implementation of equals https://pxhere.com/en/photo/1458897
  • 23. Benefits Benefits Nearly 100% of casts will just disappear! More concise No type repeating
  • 24. Feature Status Feature Status Java version Feature status JEP 14 Preview 15 Second preview 16 Final JEP 305 JEP 375 JEP 394
  • 25. 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
  • 26.
  • 27. String apply(Effect effect) { String formatted = ""; if (effect instanceof Delay) { Delay de = (Delay) effect; formatted = String.format("Delay active of %d ms.", de.getTim } else if (effect instanceof Reverb) { Reverb re = (Reverb) effect; formatted = String.format("Reverb active of type %s and roomS } else if (effect instanceof Overdrive) { Overdrive ov = (Overdrive) effect; formatted = String.format("Overdrive active with gain %d.", ov } else if (effect instanceof Tremolo) { Tremolo tr = (Tremolo) effect; formatted = String.format("Tremolo active with depth %d and r } else if (effect instanceof Tuner) { Tuner tu = (Tuner) effect; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
  • 28. formatted = String.format("Delay active of %d ms.", de.getTim formatted = String.format("Reverb active of type %s and roomS formatted = String.format("Overdrive active with gain %d.", ov formatted = String.format("Tremolo active with depth %d and r String apply(Effect effect) { 1 String formatted = ""; 2 if (effect instanceof Delay) { 3 Delay de = (Delay) effect; 4 5 } else if (effect instanceof Reverb) { 6 Reverb re = (Reverb) effect; 7 8 } else if (effect instanceof Overdrive) { 9 Overdrive ov = (Overdrive) effect; 10 11 } else if (effect instanceof Tremolo) { 12 Tremolo tr = (Tremolo) effect; 13 14 } else if (effect instanceof Tuner) { 15 Tuner tu = (Tuner) effect; 16
  • 29. String apply(Effect effect) { String formatted = ""; if (effect instanceof Delay de) { formatted = String.format("Delay active of %d ms.", de.getTim } else if (effect instanceof Reverb re) { formatted = String.format("Reverb active of type %s and roomS } else if (effect instanceof Overdrive ov) { formatted = String.format("Overdrive active with gain %d.", ov } else if (effect instanceof Tremolo tr) { formatted = String.format("Tremolo active with depth %d and r } else if (effect instanceof Tuner tu) { formatted = String.format("Tuner active with pitch %d. Muting } else if (effect instanceof EffectLoop el) { formatted = el.getEffects().stream().map(this::apply).collect } else { formatted = String format("Unknown effect active: %s " effect 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
  • 30. formatted = String.format("Delay active of %d ms.", de.getTim formatted = String.format("Reverb active of type %s and roomS formatted = String.format("Overdrive active with gain %d.", ov formatted = String.format("Tremolo active with depth %d and r formatted = String.format("Tuner active with pitch %d. Muting formatted = el.getEffects().stream().map(this::apply).collect formatted = String format("Unknown effect active: %s " effect String apply(Effect effect) { 1 String formatted = ""; 2 if (effect instanceof Delay de) { 3 4 } else if (effect instanceof Reverb re) { 5 6 } else if (effect instanceof Overdrive ov) { 7 8 } else if (effect instanceof Tremolo tr) { 9 10 } else if (effect instanceof Tuner tu) { 11 12 } else if (effect instanceof EffectLoop el) { 13 14 } else { 15 16
  • 31. Switch expression Switch expression String apply(Effect effect) { return switch(effect) { default -> String.format("Unknown effect active: %s }; } 1 2 3 4 5
  • 32. Switch expression Switch expression case Delay de -> String.format("Delay active of %d ms.", case Reverb re -> String.format("Reverb active of type %s String apply(Effect effect) { 1 return switch(effect) { 2 3 4 default -> String.format("Unknown effect active: %s 5 }; 6 } 7
  • 33. Switch expression Switch expression case Overdrive ov -> String.format("Overdrive active with ga case Tremolo tr -> String.format("Tremolo active with depth case Tuner tu -> String.format("Tuner active with pitch String apply(Effect effect) { 1 return switch(effect) { 2 case Delay de -> String.format("Delay active of %d ms.", 3 case Reverb re -> String.format("Reverb active of type %s 4 5 6 7 default -> String.format("Unknown effect active: % 8 }; 9 } 10
  • 34. Switch expression Switch expression case EffectLoop el -> el.getEffects().stream().map(this::apply String apply(Effect effect) { 1 return switch(effect) { 2 case Delay de -> String.format("Delay active of %d ms.", 3 case Reverb re -> String.format("Reverb active of type %s 4 case Overdrive ov -> String.format("Overdrive active with ga 5 case Tremolo tr -> String.format("Tremolo active with depth 6 case Tuner tu -> String.format("Tuner active with pitch 7 8 default -> String.format("Unknown effect active: % 9 }; 10 } 11
  • 35. Switch expression Switch expression String apply(Effect effect) { return switch(effect) { case Delay de -> String.format("Delay active of %d ms.", case Reverb re -> String.format("Reverb active of type %s case Overdrive ov -> String.format("Overdrive active with ga case Tremolo tr -> String.format("Tremolo active with depth case Tuner tu -> String.format("Tuner active with pitch case EffectLoop el -> el.getEffects().stream().map(this::apply default -> String.format("Unknown effect active: % }; } 1 2 3 4 5 6 7 8 9 10 11
  • 36.
  • 37. Sensible operations to the Sensible operations to the effect loop effect loop apply() setVolume(int volume) contains(Effect... effect)
  • 38. Nonsensical operations to the Nonsensical operations to the effect loop effect loop isTunerActive() isDelayTimeEqualToReverbRoomSize() isToneSuitableToPlayPrideInTheNameOfLov
  • 39. Visitor pattern Visitor pattern interface EffectVisitor<T> { T visit(Tuner effect); T visit(Delay effect); T visit(Reverb effect); // ... } class IsTunerActiveVisitor implements EffectVisitor<Boolean> { public Boolean visit(Tuner effect) { return !effect.isInTune(); } public Boolean visit(Delay effect) { return false; } public Boolean visit(Reverb effect) { return false; } // ... }
  • 40. Switch expression Switch expression String apply(Effect effect) { return switch(effect) { case Delay de -> String.format("Delay active of %d ms.", case Reverb re -> String.format("Reverb active of type %s case Overdrive ov -> String.format("Overdrive active with ga case Tremolo tr -> String.format("Tremolo active with depth case Tuner tu -> String.format("Tuner active with pitch case EffectLoop el -> el.getEffects().stream().map(this::apply default -> String.format("Unknown effect active: % }; } 1 2 3 4 5 6 7 8 9 10 11
  • 41. Switch expression Switch expression static String apply(Effect effect) { return switch(effect) { case Delay de -> String.format("Delay active of %d ms.", case Reverb re -> String.format("Reverb active of type %s case Overdrive ov -> String.format("Overdrive active with ga case Tremolo tr -> String.format("Tremolo active with depth case Tuner tu -> String.format("Tuner active with pitch case EffectLoop el -> el.getEffects().stream().map(Effect::app default -> String.format("Unknown effect active: % }; } 1 2 3 4 5 6 7 8 9 10 11
  • 42. Benefits Benefits 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
  • 43. What happens if What happens if effect effect is is null null? ? static String apply(Effect effect) { return switch(effect) { case Delay de -> String.format("Delay active of %d ms.", case Reverb re -> String.format("Reverb active of type %s case Overdrive ov -> String.format("Overdrive active with ga case Tremolo tr -> String.format("Tremolo active with depth case Tuner tu -> String.format("Tuner active with pitch case EffectLoop el -> el.getEffects().stream().map(Effect::app default -> String.format("Unknown effect active: % }; } 1 2 3 4 5 6 7 8 9 10 11
  • 44. What happens if What happens 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.", 3 case Reverb re -> String.format("Reverb active of type %s 4 case Overdrive ov -> String.format("Overdrive active with ga 5 case Tremolo tr -> String.format("Tremolo active with depth 6 case Tuner tu -> String.format("Tuner active with pitch 7 case EffectLoop el -> el.getEffects().stream().map(Effect::app 8 default -> String.format("Unknown effect active: % 9 }; 10 } 11
  • 45. Solution #1: defensive testing Solution #1: defensive testing if (effect == null) { return "Malfunctioning effect active."; } static String apply(Effect effect) { 1 2 3 4 5 return switch(effect) { 6 case Delay de -> String.format("Delay active of %d ms.", 7 case Reverb re -> String.format("Reverb active of type %s 8 case Overdrive ov -> String.format("Overdrive active with ga 9 case Tremolo tr -> String.format("Tremolo active with depth 10 case Tuner tu -> String.format("Tuner active with pitch 11 case EffectLoop el -> el.getEffects().stream().map(Effect::app 12 default -> String.format("Unknown effect active: % 13 }; 14 } 15
  • 46. Solution #2: integrate null Solution #2: integrate null check in switch check in switch case null -> return "Malfunctioning effect active."; static String apply(Effect effect) { 1 return switch(effect) { 2 3 case Delay de -> String.format("Delay active of %d ms.", 4 case Reverb re -> String.format("Reverb active of type %s 5 case Overdrive ov -> String.format("Overdrive active with ga 6 case Tremolo tr -> String.format("Tremolo active with depth 7 case Tuner tu -> String.format("Tuner active with pitch 8 case EffectLoop el -> el.getEffects().stream().map(Effect::app 9 default -> String.format("Unknown effect active: % 10 }; 11 } 12
  • 47. Combining case labels Combining case labels case null, default -> String.format("Unknown or malfunctionin static String apply(Effect effect) { 1 return switch(effect) { 2 case Delay de -> String.format("Delay active of %d ms.", 3 case Reverb re -> String.format("Reverb active of type %s 4 case Overdrive ov -> String.format("Overdrive active with ga 5 case Tremolo tr -> String.format("Tremolo active with depth 6 case Tuner tu -> String.format("Tuner active with pitch 7 case EffectLoop el -> el.getEffects().stream().map(Effect::app 8 9 }; 10 } 11
  • 48. Guarded patterns Guarded patterns String apply(Effect effect, Guitar guitar) { return switch(effect) { // (...) case Tremolo tr-> String.format("Tremolo active with depth %d case Tuner tu -> String.format("Tuner active with pitch %d. Mu case EffectLoop el -> el.getEffects().stream().map(this::apply default -> String.format("Unknown effect active: %s.", effect) }; } 1 2 3 4 5 6 7 8 9 https://openjdk.java.net/jeps/406
  • 49. Guarded patterns Guarded patterns case Tuner tu && !tu.isInTune(guitar) -> String.format("Guitar String apply(Effect effect, Guitar guitar) { 1 return switch(effect) { 2 // (...) 3 case Tremolo tr-> String.format("Tremolo active with depth %d 4 5 case EffectLoop el -> el.getEffects().stream().map(this::apply 6 default -> String.format("Unknown effect active: %s.", effect) 7 }; 8 } 9
  • 50. 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
  • 51. Guarded patterns Guarded patterns switch(effect) { // ... case Tuner tu && !tu.isInTune(guitar) -> // tuning is needed case Tuner tu -> // no tuning is needed // ... } 1 2 3 4 5 6
  • 52. Feature Status Feature Status Java version Feature status JEP 17 Preview JEP 406 https://openjdk.java.net/jeps/406
  • 54. Disclaimer Disclaimer Disclaimer Disclaimer Disclaimer I 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
  • 55. Deconstruction patterns Deconstruction patterns static String apply(Effect effect) { return switch(effect) { case Delay de -> String.format("Delay active of %d ms.", case Reverb re -> String.format("Reverb active of type %s case Overdrive ov -> String.format("Overdrive active with ga case Tremolo tr -> String.format("Tremolo active with depth case Tuner tu -> String.format("Tuner active with pitch case EffectLoop el -> el.getEffects().stream().map(Effect::app default -> String.format("Unknown effect active: % }; } 1 2 3 4 5 6 7 8 9 10 11
  • 56. Deconstruction patterns Deconstruction patterns case Overdrive(int gain) -> String.format("Overdrive active w static String apply(Effect effect) { 1 return switch(effect) { 2 case Delay de -> String.format("Delay active of %d ms.", 3 case Reverb re -> String.format("Reverb active of type %s 4 5 case Tremolo tr -> String.format("Tremolo active with depth 6 case Tuner tu -> String.format("Tuner active with pitch 7 case EffectLoop el -> el.getEffects().stream().map(Effect::app 8 default -> String.format("Unknown effect active: % 9 }; 10 } 11
  • 57. 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
  • 58. Pattern definition Pattern definition public pattern Overdrive(int gain) { gain = this.gain; } public class Overdrive implements Effect { 1 private final int gain; 2 3 public Overdrive(int gain) { 4 this.gain = gain; 5 } 6 7 8 9 10 } 11
  • 59. Deconstruction patterns Deconstruction patterns case Overdrive(int gain) -> String.format("Overdrive active w static String apply(Effect effect) { 1 return switch(effect) { 2 case Delay de -> String.format("Delay active of %d ms.", 3 case Reverb re -> String.format("Reverb active of type %s 4 5 case Tremolo tr -> String.format("Tremolo active with depth 6 case Tuner tu -> String.format("Tuner active with pitch 7 case EffectLoop el -> el.getEffects().stream().map(Effect::app 8 default -> String.format("Unknown effect active: % 9 }; 10 } 11
  • 60. Deconstruction patterns Deconstruction patterns static String apply(Effect effect) { return switch(effect) { case Delay(int timeInMs) -> String.format("Delay active of %d case Reverb(String name, int roomSize) -> String.format("Reve case Overdrive(int gain) -> String.format("Overdrive active w case Tremolo(int depth, int rate) -> String.format("Tremolo ac case Tuner(int pitchInHz) -> String.format("Tuner active with case EffectLoop(Set<Effect> effects) -> effects.stream().map(E default -> String.format("Unknown effect active: %s.", effect }; } 1 2 3 4 5 6 7 8 9 10 11
  • 61. Pattern composition Pattern composition static boolean isDelayTimeEqualToReverbRoomSize(EffectLoop effectLoop) } 1 2 3
  • 62. Pattern composition Pattern composition static boolean isDelayTimeEqualToReverbRoomSize(EffectLoop effectLoop return effectLoop.getEffects().stream() .filter(e -> e instanceof Delay || e instanceof Reverb) .map(dr -> { if (dr instanceof Delay d) { return d.getTimeInMs(); } else { Reverb r = (Reverb) dr; return r.getRoomSize(); } }).distinct().count() == 1; } 1 2 3 4 5 6 7 8 9 10 11 12 13
  • 63. Pattern composition Pattern composition static boolean isDelayTimeEqualToReverbRoomSize(EffectLoop effectLoop) if (effectLoop instanceof EffectLoop(Delay(int timeInMs), Reverb(St return timeInMs == roomSize; } return false; } 1 2 3 4 5 6
  • 64. Var and any patterns Var and any patterns // Pre-Java 10 Guitar telecaster = new Guitar("Fender Telecaster Baritone Blacktop", G // Java 10 var telecaster = new Guitar("Fender Telecaster Baritone Blacktop", Gui 1 2 3 4 5 https://openjdk.java.net/jeps/286
  • 65. Var and any patterns Var and any patterns static boolean isDelayTimeEqualToReverbRoomSize(EffectLoop effectLoop) if (effectLoop instanceof EffectLoop(Delay(int timeInMs), Reverb(St return timeInMs == roomSize; } return false; } 1 2 3 4 5 6
  • 66. Var and any patterns Var and any patterns if (effectLoop instanceof EffectLoop(Delay(var timeInMs), Reverb(v static boolean isDelayTimeEqualToReverbRoomSize(EffectLoop effectLoop) 1 2 return timeInMs == roomSize; 3 } 4 return false; 5 } 6
  • 68. Var and any patterns Var and any patterns static boolean isDelayTimeEqualToReverbRoomSize(EffectLoop effectLoop) if (effectLoop instanceof EffectLoop(Delay(var timeInMs), Reverb(_ return timeInMs == roomSize; } return false; } 1 2 3 4 5 6
  • 69. Optimization Optimization static String apply(Effect effect) { return switch(effect) { case Delay(int timeInMs) -> String.format("Delay active of %d case Reverb(String name, int roomSize) -> String.format("Reve case Overdrive(int gain) -> String.format("Overdrive active w case Tremolo(int depth, int rate) -> String.format("Tremolo ac case Tuner(int pitchInHz) -> String.format("Tuner active with case EffectLoop(var effects) -> effects.stream().map(Effect:: default -> String.format("Unknown effect active: %s.", effect }; } 1 2 3 4 5 6 7 8 9 10 11
  • 70. Optimization Optimization case EffectLoop(var effects) -> effects.stream().map(Effect::ap static String apply(Effect effect) { 1 return switch(effect) { 2 // ... 3 4 default -> String.format("Unknown effect active: %s.", effect) 5 }; 6 } 7
  • 71. Optimization Optimization case EffectLoop(Tuner(int pitchInHz), _) -> String.format("The case EffectLoop(var effects) -> effects.stream().map(Effect::ap static String apply(Effect effect) { 1 return switch(effect) { 2 // ... 3 4 5 default -> String.format("Unknown effect active: %s.", effect) 6 }; 7 } 8
  • 72. 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
  • 73. Feature Status Feature Status Java version Feature status JEP n/a Exploratory document Pattern Matching for Java https://cr.openjdk.java.net/~briangoetz/amber/pattern-match.html
  • 74. Pattern Matching Plays Pattern Matching Plays Nice With Nice 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
  • 75. Completeness on pattern switch Completeness on pattern switch expressions expressions static String apply(Object object) { return switch(object) { case Effect e -> e.apply(); case String s -> String.format("Tried to apply a String: %s", case Number n -> String.format("Tried to apply a Number: %d", }; } 1 2 3 4 5 6 7
  • 76. Completeness on pattern switch Completeness on pattern switch expressions expressions return switch(object) { // Won't compile - incomplete! static String apply(Object object) { 1 2 case Effect e -> e.apply(); 3 case String s -> String.format("Tried to apply a String: %s", 4 case Number n -> String.format("Tried to apply a Number: %d", 5 }; 6 } 7
  • 77. Completeness on pattern switch Completeness on pattern switch expressions expressions default -> String.format("Tried to apply an Object: %s", static String apply(Object object) { 1 return switch(object) { 2 case Effect e -> e.apply(); 3 case String s -> String.format("Tried to apply a String: %s", 4 case Number n -> String.format("Tried to apply a Number: %d", 5 6 }; 7 } 8
  • 78. Demo Demo Make Effect a sealed type https://pxhere.com/en/photo/1458897
  • 79. Sealed types yield Sealed types yield completeness completeness static String apply(Effect effect) { return switch(effect) { case Delay(int timeInMs) -> String.format("Delay active of %d case Reverb(String name, int roomSize) -> String.format("Reve case Overdrive(int gain) -> String.format("Overdrive active w case Tremolo(int depth, int rate) -> String.format("Tremolo ac case Tuner(int pitchInHz) -> String.format("Tuner active with case EffectLoop(Tuner(int pitchInHz), _) -> String.format("The case EffectLoop(var effects) -> effects.stream().map(Effect:: default -> String.format("Unknown effect active: %s.", effect }; } 1 2 3 4 5 6 7 8 9 10 11 12
  • 80. Sealed types yield Sealed types yield completeness completeness static String apply(Effect effect) { return switch(effect) { case Delay(int timeInMs) -> String.format("Delay active of %d case Reverb(String name, int roomSize) -> String.format("Reve case Overdrive(int gain) -> String.format("Overdrive active w case Tremolo(int depth, int rate) -> String.format("Tremolo ac case Tuner(int pitchInHz) -> String.format("Tuner active with case EffectLoop(Tuner(int pitchInHz), _) -> String.format("The case EffectLoop(var effects) -> effects.stream().map(Effect:: }; } 1 2 3 4 5 6 7 8 9 10 11 https://cr.openjdk.java.net/~briangoetz/amber/pattern-match.html
  • 81. Demo Demo Convert an implementing class to a record Acquire constructor, accessor methods etc. https://pxhere.com/en/photo/1458897
  • 82. 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
  • 83. Record patterns Record patterns record Amplifier(String name, EffectLoop stockEffects, EffectLoop auxE record EffectLoop(Delay delay, Reverb reverb) { } 1 2 static String switchOn(Amplifier amplifier) { return switch(effectLoop) { // ... case Amplifier(var name, EffectLoop(Delay(int timeInMs), Reverb // ... } } 1 2 3 4 5 6 7
  • 84. 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 contain case EffectLoop(var name, var volume, var effect) -> "Effect lo case EffectLoop(var name, var volume, var effect, ...) -> "Eff case EffectLoop(var name, var volume, var effect1, var effect2 case EffectLoop(var name, var volume, var effect1, var effect2 } } 1 2 3 4 5 6 7 8 9
  • 85. 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. Feature Status Feature Status Completeness Completeness Java version Feature status JEP 17 Preview JEP 406 https://openjdk.java.net/jeps/406
  • 87. Feature Status Feature Status Record & Array Patterns Record & Array Patterns Java version Feature status JEP 18 Preview JEP 405
  • 88. A Better A Better A Better A Better A Better Serialization Serialization Serialization Serialization Serialization ? ? ? ? ?
  • 89. 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. 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. 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
  • 92. Serialization Serialization public class EffectLoop implements Effect { private String name; private Set<Effect> effects; public EffectLoop(String name) { this.name = name; this.effects = new HashSet<>(); } } 1 2 3 4 5 6 7 8 9
  • 93. Serialization Serialization public pattern EffectLoop(String name, Effect[] effects) { name = this.name; effects = this.effects.toArray(); } public class EffectLoop implements Effect { 1 private String name; 2 private Set<Effect> effects; 3 4 public EffectLoop(String name) { 5 this.name = name; 6 this.effects = new HashSet<>(); 7 } 8 9 10 11 12 13 } 14
  • 94. Serialization Serialization public static Effectloop deserialize(String name, Effect[] effect EffectLoop effectLoop = new EffectLoop(name); for (Effect effect : effects) { this.effects.add(effect); } return effectLoop; public class EffectLoop implements Effect { 1 private String name; 2 private Set<Effect> effects; 3 4 public EffectLoop(String name) { 5 this.name = name; 6 this.effects = new HashSet<>(); 7 } 8 9 10 11 12 13 14 15 } 16
  • 95. Serialization Serialization public class EffectLoop implements Effect { private String name; private Set<Effect> effects; public EffectLoop(String name) { this.name = name; this.effects = new HashSet<>(); } @Deserializer public static EffectLoop deserialize(String name, Effect[] effect EffectLoop effectLoop = new EffectLoop(name); for (Effect effect : effects) { this.effects.add(effect); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
  • 96. 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
  • 98. 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/
  • 99. 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
  • 100. 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 // do something with name & roomSize 6
  • 101. Other ideas Other ideas Deconstruction patterns for all classes Enhanced array patterns String[] { [8] -> var eighthElement, [9] -> var ninthElement} AND patterns Patterns in catch clauses Collection patterns https://mail.openjdk.java.net/pipermail/amber-spec-experts/2021-January/002758.html
  • 103. 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 (and more similar to) constructing them. holds the potential to simplify and streamline much of the code we write today.
  • 104. Major Feature Major Feature Major Feature Major Feature Major Feature
  • 105. #jLoveConf #PatternMatching @hannotify Thank you! ☺️ Thank you! ☺️ bit.do/jlove-pattern-matching github.com/hannotify/pattern- matching-music-store hanno.codes @hannotify