1. Introduction
Kotlin enums offer an elegant way to handle multiple conditions in a switch-like structure.
In this tutorial, we’ll explore how to use enums with the when() expression and how it enhances code readability and maintainability.
2. The Basics of Enums in Kotlin
Before delving into the details of using enums with the when() expression, let’s briefly understand what enums are and how they work in Kotlin.
Enums, short for enumerations, allow us to define a set of named constant values, creating a type-safe way to represent a set of related values:
enum class Color {
RED, GREEN, BLUE
}
In this example, Color is an enum class with three values: RED, GREEN, and BLUE. Enums can have properties, methods, and even implement interfaces, making them versatile for a variety of use cases.
3. Simplifying Code With when() and Enums
One of the key advantages of enums is their seamless integration with the when() expression in Kotlin. The when() expression acts as a powerful replacement for the traditional switch() statement in other programming languages. The when() expression in Kotlin provides a concise and expressive syntax for handling multiple conditions based on the enum’s value.
Let’s consider the following example where our enum Day represents the days of the week:
enum class Day {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}
Now, let’s use the when() expression to perform different actions based on the day:
fun getDailyRoutine(day: Day): String {
return when (day) {
Day.MONDAY -> "Start of the workweek"
Day.WEDNESDAY -> "Midweek - Keep pushing!"
Day.FRIDAY -> "Almost there, the weekend is coming!"
Day.SUNDAY -> "Relax and recharge"
else -> "It's a regular day"
}
}
In this example, the when() expression handles different scenarios based on the value of the Day enum. This leads to more readable and maintainable code compared to nested if-else statements or a traditional switch() statement.
Because we haven’t covered all possible branches of our Day enum, we have to complete the when() expression with an else() clause. This is loosely equivalent to the default of a switch() statement.
3.1. Exhaustive when() Without else()
In some cases, the when() expression in Kotlin can be exhaustive and not require the else() clause. As we noted above, all when() expressions need to be exhaustive, meaning they must cover all possible branches.
Let’s consider an example involving an enum type called Color. In this example, we’ll use a when() expression without an else() clause to demonstrate its exhaustiveness:
enum class Color {
RED, GREEN, BLUE
}
fun getColorDescription(color: Color): String {
return when (color) {
Color.RED -> "The color is red."
Color.GREEN -> "The color is green."
Color.BLUE -> "The color is blue."
}
}
Here, the getColorDescription() function uses a when() expression to match each enum case of the Color enum. Since all enum cases RED, GREEN, and BLUE are covered within the when() block, there’s no need for an else() clause. This showcases the ability of when() expressions to be exhaustive without requiring additional fallback logic when all possible cases are handled.
4. Sealed Classes and when() Expression
In addition to enums, Kotlin provides sealed classes, which are commonly referred to as super enums. Sealed classes share some characteristics with enums, but they offer a different set of features. One powerful way to use sealed classes is with when() expressions.
A sealed class allows us to represent a restricted hierarchy of types similar to an enum. However, sealed classes offer more flexibility as they can include additional properties and methods. Moreover, unlike enums, sealed classes can have subclasses defined outside their declaration providing a powerful mechanism for extending hierarchies.
Let’s look at an example that defines a sealed class Shape with two subclasses, Triangle and Square:
fun main(args: Array<String>) {
val shape: Shape = Shape.Triangle
when (shape) {
Shape.Square -> println("I'm a square")
Shape.Triangle -> println("I'm a triangle")
}
}
sealed class Shape {
object Triangle : Shape()
object Square : Shape()
}
In this example, the sealed class Shape serves as a container for related subclasses Triangle and Square. The when() expression performs different actions based on the type of Shape encountered. In this case, it prints “I’m a triangle“.
It’s worth noting that when working with sealed classes, we’re also allowed to skip the else() clause in the when() expression when all branches are covered, as the Kotlin compiler can infer that we’ve covered all possible sub-classes of our sealed class.
5. Conclusion
Using enums with the when() expression in Kotlin results in code that is not only more readable but also more maintainable and robust. Enums provide a type-safe way to represent a set of related values and when combined with the concise syntax of the when() expression they offer a powerful mechanism for handling multiple conditions.
As always, the full implementation of these examples is available over on GitHub.