Step 1 of 5 · Reading · ~3 min
Learn
Control Flow
if and when
Kotlin has no ternary operator, and it does not miss one: if already produces a value.
fun main() {
val score = 72
val verdict = if (score >= 60) "pass" else "fail"
println(verdict)
}
//> pass
That is the same if you already know, used in a position where a value is expected. The last
expression in the chosen branch becomes the result.
The rule that catches everyone
An if used as an expression must have an else. An if used as a statement does not.
✓ Statement — no else needed, nothing is being produced:
if (score >= 60) println("pass")
✓ Expression — else required, because verdict has to end up holding something:
val verdict = if (score >= 60) "pass" else "fail"
✗ Does not compile — there is no value for the failing case:
val verdict = if (score >= 60) "pass"
when: a switch that grew up
when compares one subject against a list of branches. Unlike Java's switch, a branch can be
a value, several values, a range, or a type check — and there is no fall-through, so there is no
break to forget.
fun main() {
val code = 404
val meaning = when (code) {
200, 201 -> "ok"
in 300..399 -> "redirect"
in 400..499 -> "client error"
else -> "something else"
}
println(meaning)
}
//> client error
| Branch form | Matches |
|---|---|
200 -> | that exact value |
200, 201 -> | either value |
in 400..499 -> | anything inside the range |
!in 400..499 -> | anything outside the range |
is String -> | any value of that type, and smart-casts it |
else -> | everything left over |
when with no subject
Drop the parentheses and every branch becomes its own boolean test. This is the form to reach for when the conditions have nothing to do with one another.
fun main() {
val n = 84
val size = when {
n < 0 -> "negative"
n < 10 -> "small"
n < 100 -> "medium"
else -> "large"
}
println(size)
}
//> medium
Branches are tested top to bottom, and the first match wins. 84 is not below 10, is below
100, so it stops there and never looks at the rest.
Exhaustiveness
Because a when can produce a value, the compiler insists that it always produces one. Used as
an expression, a subject-less when always needs an else, and a when over an ordinary value
needs one too. Used as a plain statement, else is optional — Kotlin only enforces coverage
when something depends on the result.
Order is the whole trick
When several conditions can be true at once, the order of your branches is the logic.
Put the narrowest test first. Move the divisible-by-3 test to the top and every multiple of 15 takes that branch instead — the most specific case never gets a chance to run.
Your exercise
FizzBuzz Single reads one integer and prints FizzBuzz, Fizz, Buzz, or the number
itself. A subject-less when fits it in four branches.
The mistake the grader catches is branch order. The first visible test feeds 15, and if your
divisible-by-3 branch sits above your divisible-by-15 branch you print Fizz and fail on the
very first case. A hidden test feeds 7 and expects the bare number 7, so the final branch
must print n itself — not the letter n, and not something like Number: 7.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…