ProgrammingKotlin Developer

What is the `when` construct in Kotlin, how does it work, how does it differ from switch-case in Java, and what capabilities does it provide for handling various situations? Provide examples of different usage cases.

Pass interviews with Hintsage AI assistant

Answer.

The when construct in Kotlin is a powerful tool for controlling the program's flow, replacing the traditional switch-case from Java. when was introduced to increase expressiveness, reduce boilerplate code, and enhance type safety.

Background

In Java, the switch-case construct is limited to certain types (enum, int, String). Unlike Java, Kotlin developers sought to simplify conditional branching, making it more expressive and safe.

Problem

The limitations of switch-case in Java complicate code extension and maintainability, especially when working with collections, comparing ranges, or handling different types.

Solution

The when construct in Kotlin is versatile: it works as an expression (can return a value), supports condition checks, ranges, individual values, types, and condition combinations.

Code Example:

fun describe(obj: Any): String = when (obj) { 1 -> "One" in 2..10 -> "From two to ten" is String -> "String with length ${obj.length}" else -> "Unknown" } val res1 = describe(1) // "One" val res2 = describe(5) // "From two to ten" val res3 = describe("Kotlin") // "String with length 6" val res4 = describe(42.0) // "Unknown"

Key Features:

  • Ability to work as both expressions and statements.
  • Checks by value, type, range, and complex conditions.
  • Ensures safety when handling all cases (e.g., with sealed classes).

Trick Questions.

Can when be used without an argument?

Yes, when can be used as a replacement for a long chain of if-else statements if there is no need to check the value of a specific variable.

when { x < 0 -> println("Negative") x == 0 -> println("Zero") else -> println("Positive") }

Is the else block mandatory in the when construct?

The else block is not mandatory if all possible cases are handled, such as for enums or sealed classes. However, if there is a possibility of an uncovered case, else is required to avoid compile-time errors.

sealed class Fruit object Apple : Fruit() object Pear : Fruit() fun check(f: Fruit): String = when (f) { Apple -> "It's an apple" Pear -> "It's a pear" // No else block, and the compiler does not complain — all options considered }

Can multiple values be used in one branch of when?

Yes, multiple values can be combined with a comma.

when (value) { 0, 1 -> println("Zero or One") else -> println("Other") }

Typical Mistakes and Anti-patterns

  • Skipping the else block for incomplete options (can lead to runtime errors).
  • Overloading when with overly complex branches (violating readability).
  • Using when only as switch-case without employing type and range checks.

Real-life Example

Negative Case

In a payment system, switch-case is used to determine the operation status. When adding a new type of status, the switch was forgotten to be updated. An unhandled status leads to a silent error.

Pros:

  • Fast implementation of changes with a small number of statuses.

Cons:

  • No guarantee that all statuses are considered.
  • Implicit silent errors when new values appear.

Positive Case

In Kotlin, a sealed class is used for statuses and the when construct for handling them. When adding a new status, the compiler requires adding handling for the new case.

Pros:

  • Safe handling of all statuses.
  • Compilation error upon missing a case.

Cons:

  • The necessity for careful updating of the sealed class when expanding the system.