Как работает when-выражение и чем оно отличается от switch?
В Kotlin when — это мощная альтернатива switch из языков вроде Java, но с гораздо более широкими возможностями и гибкостью. Оно используется как выражение (возвращает значение) или как инструкция (выполняет действия без возвращения значения). when превосходит switch практически во всём: синтаксисе, выразительности, безопасности и типизации.
1. Базовый синтаксис when
val result = when (x) {
1 -> "one"
2 -> "two"
else -> "unknown"
}
Аналог в Java:
switch (x) {
case 1: return "one";
case 2: return "two";
default: return "unknown";
}
2. when может быть без аргумента
Можно использовать when как if-else if-цепочку:
when {
x < 0 -> println("Negative")
x == 0 -> println("Zero")
else -> println("Positive")
}
3. when — это выражение
Оно возвращает значение, что позволяет сразу присвоить его переменной:
val message = when (score) {
in 90..100 -> "Excellent"
in 70..89 -> "Good"
in 0..69 -> "Try again"
else -> "Invalid"
}
В отличие от Java switch, который можно использовать только как оператор (не возвращает значение напрямую).
4. Поддержка любого типа, не только Int и String
when работает не только с числами и строками, но и с объектами, типами, булевыми выражениями и т.п.
val obj: Any = "Hello"
val type = when (obj) {
is String -> "String"
is Int -> "Integer"
else -> "Unknown"
}
Java switch до версии 14 поддерживал только int, char, enum, String.
5. Работа с диапазонами и коллекциями
when (x) {
in 1..10 -> println("From 1 to 10")
in validIds -> println("Valid ID")
!in 100..200 -> println("Outside range")
}
В Java switch нельзя проверять попадание в диапазон без явного условия в case.
6. Группировка значений
Можно группировать несколько значений через запятую:
when (x) {
0, 1 -> println("Zero or One")
2, 3, 4 -> println("Two to Four")
}
В Java switch приходится писать несколько case:
switch (x) {
case 0:
case 1:
System.out.println("Zero or One");
break;
}
7. else обязателен при использовании как выражения
Если when используется для присвоения значения, обязательно нужно указать else, чтобы покрыть все возможные случаи.
val label = when (value) {
"a" -> "Alpha"
"b" -> "Beta"
else -> "Unknown"
}
8. Можно выполнять блоки кода с фигурными скобками
Если нужно выполнить несколько операций в ветке:
when (command) {
"START" -> {
println("Starting...")
startProcess()
}
"STOP" -> {
println("Stopping...")
stopProcess()
}
}
9. Использование с enum
when отлично сочетается с enum и требует обработки всех возможных значений (если не указать else, компилятор покажет ошибку, если не все покрыты):
enum class Direction { NORTH, SOUTH, EAST, WEST }
fun move(dir: Direction): String = when (dir) {
Direction.NORTH -> "Up"
Direction.SOUTH -> "Down"
Direction.EAST -> "Right"
Direction.WEST -> "Left"
}
10. Вложенные when
Можно использовать when внутри when:
when (x) {
in 1..10 -> when (y) {
in 1..5 -> println("x=1..10, y=1..5")
else -> println("x=1..10, y>5")
}
else -> println("x > 10")
}
11. Сравнение с switch
Особенность | when в Kotlin | switch в Java |
---|---|---|
Возвращает значение | ✅ Да (выражение) | ❌ Нет (до Java 14) |
--- | --- | --- |
Работает с любыми типами | ✅ Любые (Any) | ❌ Только int, char, enum, String |
--- | --- | --- |
Диапазоны и коллекции | ✅ Да (in, !in) | ❌ Нет |
--- | --- | --- |
Группировка значений | ✅ Через запятую | ❌ Только множественные case |
--- | --- | --- |
Без аргумента | ✅ Да | ❌ Нет |
--- | --- | --- |
Обязательный else | ✅ При выражении | ❌ Не обязателен |
--- | --- | --- |
Вложенность | ✅ Удобна | ❌ Муторно |
--- | --- | --- |
12. Пример: расчёт налога
fun taxRate(income: Int): Double = when {
income <= 10_000 -> 0.0
income <= 50_000 -> 0.1
income <= 100_000 -> 0.2
else -> 0.3
}
Такой код в Java выглядел бы длиннее и менее выразительно.
13. Компилятор подсказывает про непокрытые случаи
Если when используется на sealed class или enum, и ты не покрыл все случаи — компилятор напомнит. Это даёт больше безопасности.
sealed class Animal
class Cat : Animal()
class Dog : Animal()
fun sound(animal: Animal): String = when (animal) {
is Cat -> "Meow"
is Dog -> "Woof"
// else не нужен, если все подклассы покрыты
}
when — это мощный инструмент, сочетающий в себе лаконичность, выразительность и безопасность, чего switch в Java не предоставляет в полной мере.