JDK 12 has introduced some much needed change to the switch statement. Our good old switch statement is being re-vamped and can now also be used as an expression. Learn how its new design eliminates common irritants, packs succinct syntax and provides exhaustive case coverage …
Pre JDK 12 – Java Switch Statement
The Java switch statement has always been a simple statement to grasp and it’s one of the basic constructs that we’ve all been taught in Java . There is however times when one scratches their heads and wonders how on earth it’s still plagued by the following limitations …
- Cannot specify multiple case labels on a single line without repeating multiple “case” keywords.
- Unable to express a case label with pattern/range matching criteria. Must define an exact match .
- Manually manage fall-through with repetitive break statements for each case and must be careful against accidental fall-through.
- No support from compiler to ensure your covering all the cases (known as exhaustiveness).
- No real local scoping in each switch arm.
I have a friend who started learning Java this year and he intuitively tried using the switch statement with range checking an integer i.e (case < 100). He was disappointed when told by the instructor that this wasn’t supported. We had a discussion about it afterwards and it got me thinking about actually writing this post. The point is that even a novice programmer is expecting more from Java’s switch …time for improvement!
The code for this tutorial is available on MVP Java’s GitHub account here. I’ll be demonstrating the new JDK 12 switch preview feature via JShell . This has all been setup for you to run within an official Docker container with access to all the JShell *.jsh script files for you to play around with. The environment is totally reproducible with a single git clone command followed by running a Docker container via the “run.sh” script provided.
1 2 3 4 5 |
git clone https://github.com/mvpjava/jdk12-Switch-Tutorial.git // run.sh will download Docker Image and then run Docker Container // with JShell up and running run.sh |
If you want to see how to do this then check out the video version of this tutorial on MVP Java’s YouTube channel …
Java Switch Statement – The Original Gangster
Some pain points in the original switch statement is the obvious verbosity. We also have to worry about not forgetting to insert the “break;” statement at the end of every case in order to take care of accidental fall-through. Here’s an example …
Switch Statement – Scoping Issues
Notice on line 13 that the variable “thisReallyIsGlobalScope” may look like it has local scope however it doesn’t. As you can see on line 18, we can reference it because the variable scope is the entire switch statement — all cases including default.
Although you can re-use the variable name on line 18, you can’t reference its original declared value from line 13 (i.e: thisReallyIsGlobalScope++ will not result in 201) since the compiler will complain that it may not have been initialized … and it’s correct. Even if you leave out the break on line 15 to cause an intentional fall-through, this doesn’t help.
Basically scoping in the original switch statement is confusing and error prone! Some of us try to get around this and surround the variable declaration within a block of curly braces which does work in creating local scope like so …
1 2 3 4 5 |
case ACS: { double localVariable = 42; power = 140 + localVariable; } |
BUT notice we forgot the break; statement thus causing an accidental fall-through … it happens more than you think.
Switch Statement – Too Many Cases
Aren’t you tired of formatting your code on a single line just to save space to include multiple labels such as “case THERMAL: case COMS:” – see line 22. Why do we have to repeat the “case” keyword every time?
We shouldn’t have to define a default: switch arm for an enum if you think about it. There are a finite amount of possibilities listed in an enum therefore should’t we have some sort of built in support to take care of this case for us? Nothing worse than writing code that in theory will never be called.
Switch Statement or Expression?
In the end we are decorating the above switch statement to behave more like a switch expression. It is wrapped in a method in which all the switch arms assign a value to a variable and then return it. This switch statement versus expression decoration makes me think of the similar difference between a regular if statement and Java’s ternary operator. The difference being we don’t have to wrap the ternary operator in a method because it functions as an expression as is.
JDK 12 Switch – Preview Feature
Although many improvements have been made to Java’s switch statement, this is not set in stone. JDK 12 is introducing it as a preview feature which must be explicitly set in order to be enabled (as shown below). Preview features are treated as experimental before being made officially part of any future JDK release – developer feedback is welcome here at the Amber mailing list.
1 2 3 4 5 6 7 |
javac --release 12 --enable-preview Demo.java java --enable-preview Demo //OR in JShell for tutorial (setup for you in run.sh) jshell --enable-preview< YourJShellScript.jsh |
Unfortunately case labels supporting pattern/range matching (JEP 305) are not yet available in JDK 12 but we should see them in JDK 13 – that is great news and I can’t wait for that.
JDK 12 Switch – What’s new?
The JDK 12 switch statement has really been improved upon by reducing its verbosity while addressing the fall though, scoping and exhaustiveness issues with enums. Lets visit each improvement separately .
Switch Expression
You now have the choice to re-write a switch statement as a switch expression! Switch expressions are supported in both the new and traditional switch statement syntax. Lets see an example below using the following JShell command with the contents of the JShell script file.
1 |
jshell /open /root/jdk12SwitchDemoNew.jsh |
1 2 3 |
// Output from Above (from lines 1 and 25) MVP Java - JDK 12 Switch Demo - New Attitude Control System (ACS) taking 60.000 mW of Power |
A Lot has changed in the above new JDK 12 switch example but you can see that on Line 9: The switch result is being assigned to a variable, thus being used as an expression. Consequently, you must include the semi-colon on line 18!.
Verbosity – Less Is More
Stating the obvious … less verbose! The following improvements were made.
- Bye bye break statements just to prevent fall-through
- Line 17 now lists multiple switch labels separated by a comma. No need to repeat the “case” keyword anymore.
- No default case needed for enum types – exhaustiveness. The compiler inserts the default case for you and provides the following compilation error “the switch expression does not cover all possible input values“.
Enhanced Break Statement
The “break” statement can and must specify a return value when the switch is used as an expression. It’s easy to think that you need to use the “return” keyword instead but that is actually wrong.
You can’t use “return” anymore in a block to the right of the the new arrow syntax or if a traditional switch is used as an expression.
A switch expression must always compute a value or it will throw an exception
New Arrow Syntax
The new switch syntax resembles the lambda syntax since its leveraging the arrow symbol “->”. Each switch label can be written with the new “case $L ->” syntax which has the benefit of stating that only the block to the right of the arrow is executed (that’s really why we don’t need the break anymore).
The arrow form prevents fall through and needs no break statement to signify the end of its block
The new switch label syntax now restricts the block to the right of the arrow to being either
- An expression as on line 11 and 17
- A block as in “case ACS ->” on line 12 with the curly braces { … }
- Or a throw statement
Basically, something must be returned in one of the above forms.
Switch Scoping
Goodbye globally scoped variables in “case $L -> ” based switches.
Variables declared in a switch arm now only have local scope meaning no other arm can access it. If you want to use the same variable name, that’s not a problem – just declare your own copy in the switch arm. Line 14 show cases a real local variable that cannot be referenced in another switch arm.
Original Switch Syntax as an Expression
You can still opt to use the old switch syntax even as an expression if you want, both forms are acceptable.
However using the old syntax as a statement will re-invite the above pain points we discussed at the start of the post. Just remember that you must use break with a return value now (Line 12, 17, 20) since the break statement has been enhanced to return a value.
JDK 12 Switch – Wrap-up
The JDK 12 switch has had some substantial improvements made ranging from reducing verbosity to being used as an expression. Although still due for further improvements such as pattern matching and extending exhaustiveness to cover sealed types, I hope to see it part of JDK 13.
Don’t forget to check out the YouTube version of this tutorial here.
If you interested in developing Spring Boot Applications in a Docker Container then check this great Post I wrote Running Spring Tool Suite 4 in Docker.