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
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.
elseruns 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:
val label = if (score >= 50) "Pass" else "Fail"
val max = if (a > b) a else bWhen 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:
val fee = if (isMember) {
println("Member discount applied")
5.0
} else {
10.0
}when
when compares a value against a list of branches:
when (day) {
"Sat", "Sun" -> println("Weekend")
"Fri" -> println("Almost there")
else -> println("Weekday")
}- Separate several values with commas.
- Use
infor ranges:in 90..100 -> "A". - Use
isto check a type:is String -> ..., after which the value is smart cast. - Branches don't fall through, so there's no
breakto 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:
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:
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 ==:
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:
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:
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 test | Write the branch as |
|---|---|
| One of several values | "a", "b" -> |
| Inside or outside a range | in 1..9 -> or !in 1..9 -> |
| A type | is String -> or !is String -> |
| A missing value | null -> |
| Any other condition | use 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 ifandelserun the first branch whose condition is true.ifis an expression:val x = if (c) a else b; else is required then.when (value)matches exact values, comma-separated values, ranges withinand types withis.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.
Grades with when and ranges
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)}")
}
}95: A
80: B
50: C
12: Fail
140: Invalid scoreLine-by-line explanation
- Line 1The whole when is the function's result, so = replaces a block and return.
- Lines 2 to 5in checks whether the score falls inside each range, both ends included.
- Line 6else handles anything outside 0 to 100.
if as an expression
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)
}Delivery: 0.0
Total: 62.0
Thanks for shoppingLine-by-line explanation
- Line 5The basket is over 50, so delivery costs nothing: 0.0.
- Line 6Not a member, so no discount.
- Line 11if picks one of two strings directly.
when without an argument, and type checks
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)
}Int, doubled is 42
Text of length 5
no
Something else
Good eveningLine-by-line explanation
- Line 1Any is the parent of every type, so describe accepts anything.
- Lines 2 to 4After an is check, x is smart cast, so x * 2 and x.length work.
- 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
val label = if (score > 50) "Pass" // error: 'if' must have both main and 'else' branchesval label = if (score > 50) "Pass" else "Fail"Overlapping branches in the wrong order
val size = when {
n > 0 -> "positive"
n > 100 -> "huge" // never reached
else -> "zero or less"
}val size = when {
n > 100 -> "huge"
n > 0 -> "positive"
else -> "zero or less"
}Looking for a ternary operator
val max = a > b ? a : b // not valid Kotlinval max = if (a > b) a else bKotlin 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.
Complete the expression so it returns "Even" or "Odd".
val kind = if (n % 2 == 0) "Even" "Odd"
What does this print?
val x = 7
when (x) {
1, 3, 5, 7, 9 -> println("odd")
else -> println("even")
}
What does this print?
val temp = 18
val advice = when {
temp > 25 -> "hot"
temp > 15 -> "mild"
temp > 5 -> "cool"
else -> "cold"
}
println(advice)
Which when branch matches every number from 10 to 20?
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.
Does Kotlin have a
? :ternary operator?- Yes
- Only for numbers
- No, because if is an expression
- Only in when
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
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
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
What does
val y = when (2) { 1 -> "one"; 2, 3 -> "two or three"; else -> "other" }give?- "one"
- "two or three"
- "other"
- An error