kotlinbeginner

When Expression — Advanced Matching

Use when as expression and statement: type checks, ranges, destructuring, and guard conditions.

kotlin
sealed class ApiResult<out T> {
    data class Success<T>(val data: T) : ApiResult<T>()
    data class Error(val code: Int, val message: String) : ApiResult<Nothing>()
    data object Loading : ApiResult<Nothing>()
}

sealed class Shape {
    data class Circle(val radius: Double) : Shape()
    data class Rectangle(val w: Double, val h: Double) : Shape()
    data class Triangle(val base: Double, val height: Double) : Shape()
}

fun main() {
    // Basic when
    val day = 3
    val dayName = when (day) {
        1 -> "Monday"
        2 -> "Tuesday"
        3 -> "Wednesday"
        4 -> "Thursday"
        5 -> "Friday"
        6, 7 -> "Weekend"
        else -> "Unknown"
    }
    println("Day: $dayName")

    // Range matching
    val score = 85
    val grade = when (score) {
        in 90..100 -> "A"
        in 80..89 -> "B"
        in 70..79 -> "C"
        in 60..69 -> "D"
        else -> "F"
    }
    println("Grade: $grade")

    // Type checking (smart cast)
    fun describe(obj: Any): String = when (obj) {
        is String -> "String of length ${obj.length}"
        is Int -> "Int: ${obj * 2}"
        is List<*> -> "List with ${obj.size} items"
        is Map<*, *> -> "Map with ${obj.size} entries"
        !is Number -> "Not a number"
        else -> obj.toString()
    }
    println(describe("hello"))
    println(describe(42))
    println(describe(listOf(1, 2, 3)))

    // Sealed class exhaustive when
    fun processResult(result: ApiResult<String>): String = when (result) {
        is ApiResult.Success -> "Data: ${result.data}"
        is ApiResult.Error -> "Error ${result.code}: ${result.message}"
        ApiResult.Loading -> "Loading..."
    }
    println(processResult(ApiResult.Success("hello")))
    println(processResult(ApiResult.Error(404, "Not found")))

    // Shape area with when
    fun area(shape: Shape): Double = when (shape) {
        is Shape.Circle -> Math.PI * shape.radius * shape.radius
        is Shape.Rectangle -> shape.w * shape.h
        is Shape.Triangle -> 0.5 * shape.base * shape.height
    }
    println("Circle area: ${"%.2f".format(area(Shape.Circle(5.0)))}")

    // When without argument (replaces if-else chain)
    val temp = 35
    val weather = when {
        temp < 0 -> "Freezing"
        temp < 15 -> "Cold"
        temp < 25 -> "Pleasant"
        temp < 35 -> "Warm"
        else -> "Hot"
    }
    println("Weather: $weather")

    // When with complex conditions
    val x = 15
    val y = 20
    val quadrant = when {
        x > 0 && y > 0 -> "Q1"
        x < 0 && y > 0 -> "Q2"
        x < 0 && y < 0 -> "Q3"
        x > 0 && y < 0 -> "Q4"
        else -> "On axis"
    }
    println("Point ($x,$y) is in $quadrant")

    // When as statement with block bodies
    val input = "quit"
    when (input.lowercase()) {
        "start", "begin" -> {
            println("Starting process...")
            println("Initialized")
        }
        "stop", "quit", "exit" -> {
            println("Stopping...")
            println("Goodbye!")
        }
        else -> println("Unknown command: $input")
    }
}

Use Cases

  • Exhaustive sealed class handling
  • Complex conditional logic replacement
  • Type-safe pattern matching

Tags

Related Snippets

Similar patterns you can reuse in the same workflow.