Hello! Welcome to your sixth lesson in the "Learn Kotlin Syntax" course.
In our last lesson, we explored how if can be used as an expression in Kotlin, allowing for more concise and immutable code. We saw how this replaces the need for Java's ternary operator and often lets us use val instead of var.
Today, we'll build directly on that concept by exploring one of Kotlin's most powerful and flexible control flow structures: the when expression. The learning outcome for this lesson is to implement a 'when' expression to replace a traditional Java 'switch' statement for concise conditional logic. You'll see that when is not only a more elegant replacement for Java's switch, but also a significant improvement over long if-else-if chains.
1. From Java switch to Kotlin when
Given your experience with Java, you are well-acquainted with the switch statement. It's useful, but it has some well-known drawbacks, such as the mandatory break statements to prevent "fall-through" and its limited applicability.
Kotlin's when expression addresses these issues directly. Let's start by seeing how when serves as a modern replacement for switch.
#14 Kotlin Tutorial When Expression
This video from Telusko provides an excellent transition from the familiar Java switch to Kotlin's when. It starts by reviewing the switch statement and then introduces the cleaner when syntax.
Please watch from the beginning to 04:09. Pay attention to: The review of Java's switch syntax, including case and break (00:00 - 01:55). The introduction of Kotlin's when keyword and the -> syntax (02:20 - 03:47). How the else keyword replaces default for handling unmatched cases (03:47 - 04:09).
As you saw, when is syntactically cleaner and more intuitive. Let's recap the key differences from Java's switch:
- No
breakneeded:whenautomatically executes only the code for the matching branch. This prevents the common bug of forgetting abreakstatement. ->operator: Branches are defined with an arrow (->) instead of a colon.elsefor default: Thedefaultcase is replaced by a more conventionalelsebranch.
Here's a side-by-side comparison:
Java switch
int day = 2;
String dayName;
switch (day) {
case 1: dayName = "Monday"; break;
case 2: dayName = "Tuesday"; break;
default: dayName = "Some other day"; break;
}
Kotlin when (as a statement)
val day = 2
when (day) {
1 -> println("Tuesday")
2 -> println("Tuesday")
else -> println("Some other day")
}
2. when as an Expression
Just like if, when is an expression in Kotlin, meaning it can evaluate to a value. This is where its power truly begins to show, allowing you to write even more concise and functional code.
Let's continue with the same video to see this in action.
#14 Kotlin Tutorial When Expression
This next segment demonstrates how to use when as an expression, assigning its result directly to a variable.
Watch from 05:21 to 07:27. Notice how the when block's result is assigned to the str variable, making the code more declarative.
By using when as an expression, we can refactor our previous example to be much cleaner:
val day = 2
val dayName = when (day) {
1 -> "Monday"
2 -> "Tuesday"
else -> "Some other day"
}
println(dayName) // Prints "Tuesday"
Notice that we can assign the result directly to an immutable val. When when is used as an expression, the compiler enforces that all possible paths return a value. This means the else branch is usually mandatory, ensuring your expression is exhaustive.
3. The Versatility of when
when is far more than just a switch replacement. It supports a variety of conditions that make it incredibly versatile. The following article from Baeldung provides a great overview of these advanced capabilities.
Guide to the “when{}” Block in Kotlin
The article 'Guide to the “when{}” Block in Kotlin' from Baeldung is a comprehensive resource. We will focus on the sections that demonstrate how when goes beyond a simple switch.
Please read the following sections to understand the advanced features of when: Section 2.5, 'Combining when{} Cases': Learn how to use a comma to handle multiple values in a single branch. Section 2.8, 'Range and Collection Case Expressions': See how to use the in keyword to check for values within a range (1..10) or a collection. Section 2.9, 'is Case Operator and Smart Cast': Discover how to check an object's type with is and how Kotlin automatically smart-casts the variable for you. Section 2.6, 'when{} Used Without an Argument': Understand how when can be used without a subject, acting as a more readable if-else-if chain.
Let's summarize those powerful features with some examples:
-
Combining multiple values:
val code = 200 when (code) { 200, 201, 202 -> println("Success") else -> println("Not a success code") } -
Using ranges:
val httpStatus = 404 val statusCategory = when (httpStatus) { in 200..299 -> "Success" in 300..399 -> "Redirection" in 400..499 -> "Client Error" in 500..599 -> "Server Error" else -> "Unknown" } println(statusCategory) // Prints "Client Error" -
Checking types (with smart casting):
fun processValue(value: Any) { when (value) { is String -> println("It's a String of length ${value.length}") // value is smart-cast to String is Int -> println("It's an Int with value $value") // value is smart-cast to Int else -> println("It's some other type") } } processValue("Hello Kotlin") // Prints "It's a String of length 12" -
whenwithout an argument: This is perfect for replacing complexif-else-ifchains.val name = "Alex" val number = 42 when { name.startsWith("A") -> println("Name starts with A") number > 50 -> println("Number is large") else -> println("No condition met") }
4. Hands-On Practice
In the previous lesson, you wrote a function getStatusMessage using an if-else-if ladder. Let's refactor it to use when and add more sophisticated logic.
Goal: Refactor the getStatusMessage function to use a when expression and handle ranges of HTTP status codes.
- Open the Kotlin file from your previous exercise.
- Modify the
getStatusMessage(statusCode: Int): Stringfunction. - Replace the
if-else-ifchain with a singlewhenexpression that returns the status category as aString. - Use ranges to categorize the codes:
200..299should return"Success".300..399should return"Redirection".400..499should return"Client Error".500..599should return"Server Error".
- Handle the specific code
418separately to return"I'm a teapot". - For all other codes, use an
elsebranch to return"Unknown Category". - In your
mainfunction, test your refactored function with codes like200,302,404,418,503, and100.
Click to see a possible solution
fun getStatusMessage(statusCode: Int): String {
return when (statusCode) {
in 200..299 -> "Success"
in 300..399 -> "Redirection"
418 -> "I'm a teapot" // Specific cases are checked before ranges if placed first
in 400..499 -> "Client Error"
in 500..599 -> "Server Error"
else -> "Unknown Category"
}
}
fun main() {
println("Code 200: ${getStatusMessage(200)}") // Expected: Success
println("Code 302: ${getStatusMessage(302)}") // Expected: Redirection
println("Code 404: ${getStatusMessage(404)}") // Expected: Client Error
println("Code 418: ${getStatusMessage(418)}") // Expected: I'm a teapot
println("Code 503: ${getStatusMessage(503)}") // Expected: Server Error
println("Code 100: ${getStatusMessage(100)}") // Expected: Unknown Category
}
Note how much more readable and maintainable this version is compared to a long if-else-if chain.
Conclusion
In this lesson, you've mastered Kotlin's when expression, a powerful tool for conditional logic. You've seen how it improves upon Java's switch statement and provides a cleaner alternative to complex if-else structures.
Key Takeaways:
whenis Kotlin's modern replacement forswitch, eliminating the need forbreakstatements.- Like
if,whenis an expression that returns a value, enabling more declarative and immutable code. - The
elsebranch is mandatory whenwhenis used as an expression to ensure all possibilities are handled. whenis highly versatile, supporting conditions like multiple values, ranges (in), and type checks (is) with smart casting.
Next Lesson Preview:
We are now concluding the "Kotlin Fundamentals" module. In our next lesson, we will begin a new module, "Null Safety and Advanced Functions". The first topic is one of Kotlin's most celebrated features: nullability. We will explore how Kotlin's type system is designed to help you avoid NullPointerExceptions, a frequent source of bugs in Java. You'll learn the difference between nullable and non-nullable types and how to work with them safely.