Introduction: Goodbye, switch-case? Long live when!
If you came to Kotlin from the world of Java, C#, or JavaScript, the first thing you are probably looking for is the familiar switch-case statement. And here a surprise awaits you: in Kotlin there is no classic switch-case. Instead, the language offers a much more powerful and flexible tool — when.
On Stack Overflow, the question "How to implement switch-case statement in Kotlin" gathers thousands of views. This is normal: developers get used to certain constructs and want to find their equivalents. But the truth is that when in Kotlin is not just a replacement for switch. It is its evolution, which under the hood works smarter and faster.
In this article, we will not just show how to write when. We will look under the hood: find out what your code compiles into, why it is faster than switch in some scenarios, and how to use when to its full potential.
1. Basic syntax: from switch-case to when
To start — the simplest example. Let's imagine we have a good old Java construct:
// Javaint day = 3;String dayName;switch (day) { case 1: dayName = "Monday"; break; case 2: dayName = "Tuesday"; break; case 3: dayName = "Wednesday"; break; default: dayName = "Unknown day";}In Kotlin it will look like this:
// Kotlinval day = 3val dayName = when (day) { 1 -> "Monday" 2 -> "Tuesday" 3 -> "Wednesday" else -> "Unknown day"}Already here you can see two main advantages:
- No break — Kotlin automatically exits the block after executing a branch.
- Returns a value — you can assign the result to a variable.
2. How when works under the hood: bytecode and optimization
Now for the interesting part. When you write when, the Kotlin compiler analyzes your conditions and selects the optimal execution method. Let's look at the bytecode (approximately, without unnecessary details).
Case 1: when with constants (like switch-case)
If you use when with integers, strings, or enum constants, the compiler generates a jump table (tableswitch or lookupswitch). This is the same mechanism that Java uses for switch-case. The difference is that Kotlin does this automatically, without your involvement.
Case 2: when with arbitrary conditions
If you write something like:
when (x) { in 1..10 -> "Small" in 11..100 -> "Medium" else -> "Large"}The compiler cannot use a jump table. It generates a chain of if-else. But Kotlin does this as efficiently as possible: conditions are checked in order, and as soon as a match is found, execution stops.
Case 3: when without an argument
This is a special kind of magic. If you write:
when { x > 0 -> "Positive" x < 0 -> "Negative" else -> "Zero"}The compiler turns this into ordinary if-else. But the syntax is much cleaner than nested ifs.
Conclusion: Kotlin does not simply copy switch-case. It intelligently chooses between a jump table and if-else to make your code run as fast as possible.
3. Advanced when features: things switch doesn't have
when can do much more than just compare values. Here are a few killer features:
3.1. Type checking (smart cast)
fun describe(obj: Any): String = when (obj) { is String -> "String of length ${obj.length}" // smart cast to String is Int -> "Integer" is List<*> -> "List of ${obj.size} elements" else -> "Unknown type"}