‘when’ expression in Kotlin VS ‘switch’ statement in Java
Switch in Java
Consider the following code in Java
Widespread pattern, isn’t it? There are several things wrong with it! First, Foo f
variable is not final,
so it can be ocassionally changed in the future after some code changes.
Next, we switll have default
branch which is not necessary as we cover all enum values. But if
someone dares to add extra enum value, this code will still compile correctly!
Enough problems? Nope! I forgot break;
in each case
branch. Surprise.
An improvement is still possible to solve some of the problems above. Use return
statement! So we have
Is it better now? More or less yes. But would you create an additional function for every switch
? I’m not sure.
When in Kotlin
The equivalent constuction to switch
in Java is when
in Kotlin. You may take a look to the
when expression documentation
for more details. Note, when
expression is more functional than switch
in Java.
This was just one-to-one conversion to Kotlin and I see the warning to convert var f
to val f
at first.
It is good to notice, when
can be used as expression! We may avoid assigning f
variable inside each case.
The right of ->
is also an expression. If you need more things to do, use {
and }
. There is no break
exists or required.
If when
is used as expression, else
branch is not necessary, the compiler can prove all branches are included.
At least this works if you checking enum or
sealed classes.
Compilation fails if a missing branch is detected.
Overall I turn the example into this:
Looks concise, isn’t it?
Generated bytecode
Let’s look into bytecode for the when
statement call. Note. I use IntelliJ IDEA 2017.1 EAP with Kotlin
1.0.6 plugin. The generated bytecode may change with a future version of tools.
From the bytecode we see it throws kotlin/NoWhenBranchMatchedException
in case it turned out
there is an additional case. For example, this may happen if we are running a compiled code
againt updated Bar
enum with additional case added.
Still, a re-compilation will show there is an errors.
The only problem is that NoWhenBranchMatchedException
contains no information on what
kind of instance was there, maybe a toString()
or getClass().getName()
were nice to
have helpers. Still, in general, such calls may also throw exceptions.
Conclusion
In this post we see how when
expression can help one avoid trivial errors
in switches. We discussed the benefit of using when
as expression