Abstract: The enhanced switch is cool. Pattern Matching for switch is super cool (they even timed the JEP number to be exactly 420 - or was that fate?). But what happens when we use "break" inside the case statement? Let's find out.
Welcome to the 300th edition of The Java(tm) Specialists' Newsletter, sent to you from a sunny Crete. And that is good, because for the last few years, every time it rained, our power would trip. Fortunately we live in one of the driest parts of Crete, which itself is rather dry. We "solved" the issue by turning off all the lights outside. After a day of rain, the sun came out again, and we could turn our lights back on. That's like rebooting to see if the race condition is gone. We are finally getting round to sorting that out. Seems that exposed wires from an ancient motion sensor could perhaps be the culprit!
javaspecialists.teachable.com: Please visit our new self-study course catalog to see how you can upskill your Java knowledge.
By now, most of us have seen pattern matching used with instanceof. For example, here is an old equals() method from Person:
public final boolean equals(Object o) { if (!(o instanceof Person)) return false; Person p = (Person) o; return firstName.equals(p.firstName) && lastName.equals(p.lastName) && dateOfBirth.equals(p.dateOfBirth); }
And here is the new version with pattern matching on instanceof:
public boolean equals(Object o) { return o instanceof Person p && firstName.equals(p.firstName) && lastName.equals(p.lastName) && dateOfBirth.equals(p.dateOfBirth); }
Much nicer, we no longer need the explicit cast.
In Java 18-Preview, we can do pattern matching on the new enhanced switch statement. Furthermore, if the classes are sealed, then the compiler will check whether we have covered all cases. Let's begin with a simple sealed interface that has four implementations.
package eu.javaspecialists.tjsn.issue300; public sealed interface Colour { final class Red implements Colour {} final class Green implements Colour {} final class Blue implements Colour {} final class Orange implements Colour {} }
I will be the first to admit that this example is a bit contrived. A better example is the Style interface that you will find in JDK-18. It has three inner records for three types of styles. Nevertheless, let's continue with our terrible example.
In the next class, we iterate over a list of Colour objects,
and depending on the type, we print out the HTML equivalent
of each colour. Note that the last
else
branch is dead code - since
Colour
is a sealed
interface, only the four colours that are contained inside
as nested classes will be allowed as implementations. Thus
the AssertionError
will never be thrown.
Another oddity is the break
when we
encounter the first Blue colour. The break will leave from
the for
loop.
import eu.javaspecialists.tjsn.issue300.Colour.*; public class IfElseInstanceof { public static void main(String... args) { Colour[] colours = {new Red(), new Red(), new Green(), new Blue(), new Green(), new Orange()}; for (Colour colour : colours) { if (colour instanceof Red) { System.out.println("#FF0000 // Red"); } else if (colour instanceof Green) { System.out.println("#008000 // Green"); } else if (colour instanceof Blue) { System.out.println("#0000FF // Blue"); break; // stop when we encounter the first Blue } else if (colour instanceof Orange) { System.out.println("#FFA500 // Orange"); } else { throw new AssertionError( "Unknown Colour: " + colour.getClass()); } } } }
The output when we run this code is:
#FF0000 // Red #FF0000 // Red #008000 // Green #0000FF // Blue
Let's turn this into the enhanced switch, with pattern matching for instanceof. For more information of how this works, please refer to JEP 420 (and before the recent offer by Elon Musk for Twitter, I had no idea that 420 had another meaning ...)
One thing you will notice is that it is no longer necessary to check that we have covered all cases. If we forget one of the possible classes, then the compiler will complain.
import eu.javaspecialists.tjsn.issue300.Colour.*; public class EnhancedSwitchWithPatternMatching { public static void main(String... args) { Colour[] colours = {new Red(), new Red(), new Green(), new Blue(), new Green(), new Orange()}; for (Colour colour : colours) { switch (colour) { case Red r -> System.out.println("#FF0000 // Red"); case Green g -> System.out.println("#008000 // Green"); case Blue b -> { System.out.println("#0000FF // Blue"); break; // stop when we encounter the first Blue } case Orange o -> System.out.println("#FFA500 // Orange"); } } } }
When we run it, we see this output:
#FF0000 // Red #FF0000 // Red #008000 // Green #0000FF // Blue #008000 // Green #FFA500 // Orange
Huh? That's not correct. Why didn't it stop once it got to Blue?
The reason should be fairly obvious to those whose minds have been distorted by decades of programming in C or Java. In the old switch statement, if we did not add a break at the end of a case, then we would fall through to the next case. In the enhanced switch statement, the break is implied. Thus if we do add a break, should that not then apply to the context outside of the switch? It appears not. The reason is that we might want to have a fairly complex statement that breaks out of the switch at a different place besides the end.
An easy workaround is to add a label to the for-loop, and then we can do a labelled break to leave the loop altogether:
import eu.javaspecialists.tjsn.issue300.Colour.*; public class EnhancedSwitchWithLabelledBreak { public static void main(String... args) { Colour[] colours = {new Red(), new Red(), new Green(), new Blue(), new Green(), new Orange()}; out: for (Colour colour : colours) { switch (colour) { case Red r -> System.out.println("#FF0000 // Red"); case Green g -> System.out.println("#008000 // Green"); case Blue b -> { System.out.println("#0000FF // Blue"); break out; // stop when we encounter the first Blue } case Orange o -> System.out.println("#FFA500 // Orange"); } } } }
And now the output is the same as the if-else statements:
#FF0000 // Red #FF0000 // Red #008000 // Green #0000FF // Blue
Eureka!
Kind regards
Heinz
We are always happy to receive comments from our readers. Feel free to send me a comment via email or discuss the newsletter in our JavaSpecialists Slack Channel (Get an invite here)
We deliver relevant courses, by top Java developers to produce more resourceful and efficient programmers within their organisations.