Kotlin if and when

Make decisions with if, else if and else, use if as an expression that returns a value, and replace long chains with when.

Lesson 6 of 43Beginner19 min read

Programs make decisions all the time. Show a discount if the basket is over £50. Greet the user differently in the morning and the evening. Give a grade based on a score. In Kotlin, these decisions are written with if and when.

Kotlin's conditions have a twist that makes code shorter and safer: they're expressions, so they can produce a value. Instead of declaring a variable and assigning it in each branch, you write val label = if (score >= 50) "Pass" else "Fail". That's also why Kotlin has no ? : ternary operator; if does the job.

when is Kotlin's much more powerful version of switch. It can match exact values, several values at once, ranges and types, and it can replace long else if chains. In this lesson you'll use both, and learn when each reads best.

if, else if and else

Kotlin
if (temperature > 25) {
    println("Shorts weather")
} else if (temperature > 15) {
    println("Bring a jumper")
} else {
    println("Coat on")
}
  • The condition in brackets must be a Boolean.
  • Kotlin checks each condition from top to bottom and runs only the first branch that's true.
  • else runs when nothing else matched.
  • With a single statement, the braces are optional, but adding them keeps code consistent and safe to extend.

if as an expression

Because if produces a value, you can assign its result directly:

Kotlin
val label = if (score >= 50) "Pass" else "Fail"
val max = if (a > b) a else b

When if is used as an expression, the else branch is required, so every possible case produces a value. In a block with several lines, the last expression in the block is the value:

Kotlin
val fee = if (isMember) {
    println("Member discount applied")
    5.0
} else {
    10.0
}

when

when compares a value against a list of branches:

Kotlin
when (day) {
    "Sat", "Sun" -> println("Weekend")
    "Fri" -> println("Almost there")
    else -> println("Weekday")
}
  • Separate several values with commas.
  • Use in for ranges: in 90..100 -> "A".
  • Use is to check a type: is String -> ..., after which the value is smart cast.
  • Branches don't fall through, so there's no break to forget.

when without an argument, and as an expression

Without an argument, each branch is a full condition, which neatly replaces an else if chain:

Kotlin
val advice = when {
    temp > 25 && sunny -> "Sun cream"
    temp > 25 -> "Stay cool"
    raining -> "Umbrella"
    else -> "Enjoy your day"
}

Like if, when can return a value. When it does, it must be exhaustive: every possible input must be handled, usually with else. For enums and sealed classes, the compiler can check you've covered every case without needing else, as the enums and sealed classes lesson shows.

Capturing the subject with when (val ...)

Often the value you want to test is the result of a calculation, such as cleaned-up user input. You can compute it and give it a name right inside the brackets of when:

Kotlin
when (val cmd = readCommand().trim().lowercase()) {
    "start" -> println("Starting")
    "stop", "quit" -> println("Stopping")
    else -> println("Unknown command: $cmd")
}

The name cmd exists only inside the when, so it can't leak into the rest of the function and be used by mistake later. The value is computed once, even though several branches compare against it.

Branch conditions don't have to be literal values either. Any expression works, and Kotlin compares the subject with its result using ==:

Kotlin
fun shippingBand(country: String) = when (val code = country.uppercase()) {
    "GB" -> "Domestic"
    in setOf("FR", "DE", "ES") -> "Europe"
    else -> "International ($code)"
}

Here shippingBand("de") gives "Europe" and shippingBand("jp") gives "International (JP)". Notice how converting to upper case once, in the subject, means no branch has to worry about the user typing lower case.

Negative checks and null in when

You can flip in and is with an exclamation mark. Branches are still checked from top to bottom, so put the rejections first and let the happy path fall through to else:

Kotlin
fun check(x: Any) = when (x) {
    !is Int -> "not a number"
    !in 0..10 -> "out of range"
    else -> "ok"
}

check("a") gives "not a number", check(42) gives "out of range" and check(4) gives "ok". By the time the second branch runs, Kotlin already knows x is an Int, so the range check is allowed.

when also handles nullable values neatly. A null branch catches the missing case, and after it the value is smart cast to non-null:

Kotlin
val text = when (nickname) {
    null -> "missing"
    "" -> "empty"
    else -> "has ${nickname.length} letters"
}

This is often tidier than an if (nickname == null) ... else if (nickname.isEmpty()) chain, and it reads like a table of cases.

You want to testWrite the branch as
One of several values"a", "b" ->
Inside or outside a rangein 1..9 -> or !in 1..9 ->
A typeis String -> or !is String ->
A missing valuenull ->
Any other conditionuse when with no subject

Kotlin Conditions Syntax

Conditions

if (cond) { ... } else if (other) { ... } else { ... }
val x = if (cond) a else b

when (value) {
    1, 2 -> ...
    in 3..9 -> ...
    is String -> ...
    else -> ...
}
val y = when { cond1 -> a; cond2 -> b; else -> c }

Kotlin Conditions Summary

  • if, else if and else run the first branch whose condition is true.
  • if is an expression: val x = if (c) a else b; else is required then.
  • when (value) matches exact values, comma-separated values, ranges with in and types with is.
  • when { } without an argument replaces long if-else chains.
  • A when used as an expression must be exhaustive, usually with else.

Kotlin Conditions Examples

Each example shows the code, the output it produces and what each part does.

Example 1

Grades with when and ranges

Kotlin
fun grade(score: Int): String = when (score) {
    in 90..100 -> "A"
    in 75..89 -> "B"
    in 50..74 -> "C"
    in 0..49 -> "Fail"
    else -> "Invalid score"
}

fun main() {
    for (s in listOf(95, 80, 50, 12, 140)) {
        println("$s: ${grade(s)}")
    }
}
Output
95: A
80: B
50: C
12: Fail
140: Invalid score
Line-by-line explanation
  1. Line 1The whole when is the function's result, so = replaces a block and return.
  2. Lines 2 to 5in checks whether the score falls inside each range, both ends included.
  3. Line 6else handles anything outside 0 to 100.
Example 2

if as an expression

Kotlin
fun main() {
    val basket = 62.0
    val isMember = false

    val delivery = if (basket >= 50) 0.0 else 4.99
    val discount = if (isMember) basket * 0.1 else 0.0
    val total = basket + delivery - discount
    println("Delivery: $delivery")
    println("Total: $total")

    val message = if (total > 100) "Big order!" else "Thanks for shopping"
    println(message)
}
Output
Delivery: 0.0
Total: 62.0
Thanks for shopping
Line-by-line explanation
  1. Line 5The basket is over 50, so delivery costs nothing: 0.0.
  2. Line 6Not a member, so no discount.
  3. Line 11if picks one of two strings directly.
Example 3

when without an argument, and type checks

Kotlin
fun describe(x: Any): String = when (x) {
    is Int -> "Int, doubled is ${x * 2}"
    is String -> "Text of length ${x.length}"
    is Boolean -> if (x) "yes" else "no"
    else -> "Something else"
}

fun main() {
    println(describe(21))
    println(describe("hello"))
    println(describe(false))
    println(describe(3.5))

    val hour = 19
    val greeting = when {
        hour < 12 -> "Good morning"
        hour < 18 -> "Good afternoon"
        else -> "Good evening"
    }
    println(greeting)
}
Output
Int, doubled is 42
Text of length 5
no
Something else
Good evening
Line-by-line explanation
  1. Line 1Any is the parent of every type, so describe accepts anything.
  2. Lines 2 to 4After an is check, x is smart cast, so x * 2 and x.length work.
  3. Lines 15 to 19Without an argument, each branch is a full condition, checked in order.

Common Kotlin Conditions Mistakes

Using if as an expression without else

Don't
val label = if (score > 50) "Pass"     // error: 'if' must have both main and 'else' branches
Do
val label = if (score > 50) "Pass" else "Fail"

Overlapping branches in the wrong order

Don't
val size = when {
    n > 0 -> "positive"
    n > 100 -> "huge"        // never reached
    else -> "zero or less"
}
Do
val size = when {
    n > 100 -> "huge"
    n > 0 -> "positive"
    else -> "zero or less"
}

Looking for a ternary operator

Don't
val max = a > b ? a : b         // not valid Kotlin
Do
val max = if (a > b) a else b

Kotlin Conditions in Real Projects

Conditions in apps

Android apps use when to show the right screen for each state, such as loading, error or content, and to react to which button was tapped. Server code uses it to route requests by type. Because when over an enum or sealed class must be exhaustive, adding a new state makes the compiler point at every place that needs updating.

Kotlin Conditions FAQ

Does a Kotlin when statement fall through like a Java switch?

No. Only the first matching branch runs, and then the when ends, so there's no break to add. If several values should share the same code, list them in one branch separated by commas, for example "Sat", "Sun" -> println("Weekend").

Is else always required in a Kotlin when?

Only when the when is used as an expression that produces a value, or when its subject is a Boolean, enum or sealed type whose cases you haven't all listed. A when used purely as a statement, just to run some code, can leave out else, and then nothing happens if no branch matches.

How do I compare strings ignoring case in a when?

Convert the subject once, for example when (answer.lowercase()) { "yes", "y" -> ... }, and write every branch in lower case. For a single comparison in an if, a.equals(b, ignoreCase = true) does the same job without creating a new string.

Can I use && and || inside a when branch?

Not in a when with a subject, where each branch is a value to compare against. Use a when without a subject instead, where every branch is a full Boolean condition such as temp > 25 && sunny ->. You can still combine several values with commas in a subject when, which works like "or".

Should I use if or when for a simple true/false choice?

Use if. val label = if (passed) "Pass" else "Fail" is shorter and clearer than a when with true and false branches. Reach for when once you have three or more cases, or when you're comparing one value against a list of options.

Kotlin Conditions Exercises

Answer each one and check it instantly. If you get stuck, open the hint before the answer.

Fill in the blankseasy

Complete the expression so it returns "Even" or "Odd".

val kind = if (n % 2 == 0) "Even"  "Odd"
Predict the outputeasy

What does this print?

val x = 7
when (x) {
    1, 3, 5, 7, 9 -> println("odd")
    else -> println("even")
}
Predict the outputmedium

What does this print?

val temp = 18
val advice = when {
    temp > 25 -> "hot"
    temp > 15 -> "mild"
    temp > 5 -> "cool"
    else -> "cold"
}
println(advice)
Multiple choicemedium

Which when branch matches every number from 10 to 20?

Multiple choicehard

What value does this block produce?

val result = if (true) {
    println("checking")
    42
} else {
    0
}

Kotlin Conditions Quiz

5 questions to check what you learned.

  1. Does Kotlin have a ? : ternary operator?

    • Yes
    • Only for numbers
    • No, because if is an expression
    • Only in when
  2. Do when branches fall through to the next branch?

    • Yes, unless you add break
    • Only for strings
    • Only without else
    • No, only the matching branch runs
  3. What does is String -> check in a when branch?

    • Whether the value's type is String
    • Whether the value equals "String"
    • Whether the value is empty
    • Whether it's a variable
  4. When must a when expression have an else branch?

    • When it returns a value and the compiler can't prove every case is covered
    • Always
    • Never
    • Only with ranges
  5. What does val y = when (2) { 1 -> "one"; 2, 3 -> "two or three"; else -> "other" } give?

    • "one"
    • "two or three"
    • "other"
    • An error