Что делает оператор ?: в Kotlin? (Elvis Operator)
Оператор Элвиса (Elvis Operator) в Kotlin
Оператор ?: называется Elvis Operator (оператор Элвиса) — из-за схожести с причёской Элвиса Пресли, если повернуть голову набок. Он используется для обработки null-значений и является краткой формой тернарного оператора, который есть в Java, но отсутствует в Kotlin.
Как он работает?
Оператор ?: проверяет выражение слева от себя. Если оно не равно null, то возвращается это значение. Если слева null, то возвращается значение справа. То есть:
val result = a ?: b
// Эквивалентно:
val result = if (a != null) a else b
Пример с вашим кодом
val name: String? = null
val result = name ?: "Unknown"
println(result) // Выведет: Unknown
val name2: String? = "Alice"
val result2 = name2 ?: "Unknown"
println(result2) // Выведет: Alice
Когда name равен null, оператор подставляет значение справа — "Unknown". Когда name2 не равен null, возвращается "Alice".
Использование с функциями и цепочками
Оператор Элвиса можно использовать с любыми выражениями, включая вызовы функций:
fun getDefaultName(): String {
println("Вызвана getDefaultName()")
return "Default"
}
val name: String? = null
val result = name ?: getDefaultName() // Вызовется getDefaultName()
println(result) // Default
val name2: String? = "Bob"
val result2 = name2 ?: getDefaultName() // getDefaultName() НЕ вызовется
println(result2) // Bob
Важно: выражение справа вычисляется лениво — только если слева null. Это повышает производительность.
Цепочки операторов
Можно объединять несколько ?: для последовательных fallback-значений:
val primary: String? = null
val secondary: String? = null
val fallback = "Final"
val result = primary ?: secondary ?: fallback
println(result) // Final
Сочетание с безопасным вызовом (?.)
Очень часто ?: используется вместе с оператором безопасного вызова ?.:
data class User(val name: String?)
fun getUser(): User? = null
val userName = getUser()?.name ?: "Guest"
println(userName) // Guest
Здесь getUser() возвращает null, поэтому ?.name тоже даёт null, и срабатывает ?:.
Подводные камни
- Тип результата: Если слева не-null тип, а справа другой тип, Kotlin выведет общий тип. Например,
val x: Any = "str" ?: 42— тип будетAny. - Не путать с Java: В Java
?:нет. Вместо него используютif-elseилиOptional.ofNullable(...).orElse(...). - Нельзя использовать для присваивания в
varс умным приведением:var x: String? = null; x ?: "default"— это выражение, оно не меняетx. - Правая часть может быть блоком:
val result = x ?: run { println("fallback"); "default" }.
Заключение
Оператор Элвиса — элегантный способ обработки null в Kotlin. Он делает код чище и читаемее, заменяя громоздкие if-else конструкции. Используйте его везде, где нужно предоставить значение по умолчанию для nullable-переменной.
Альтернативный взгляд: оператор Элвиса как частный случай when
Хотя оператор ?: очень удобен, важно понимать, что это не единственный способ обработки null. В некоторых ситуациях лучше использовать when или if-else для большей гибкости.
Например, если вам нужно не просто подставить значение, а выполнить разные действия в зависимости от null:
val name: String? = null
// С оператором Элвиса — только подстановка значения
val greeting = "Hello, ${name ?: "Guest"}!"
// С when — можно выполнить разную логику
val greeting2 = when (name) {
null -> "Hello, Guest! (anonymous)"
"Admin" -> "Hello, Admin! (privileged)"
else -> "Hello, $name! (regular user)"
}
Когда стоит избегать ?:
- Если правая часть сложная или имеет побочные эффекты — лучше использовать
if-elseдля ясности. - Если вам нужно обработать несколько разных случаев —
whenбудет читаемее. - Если вы работаете с коллекциями и хотите не только подставить значение, но и отфильтровать null — используйте
filterNotNull()илиmapNotNull().
Пример с коллекциями:
val list = listOf("Alice", null, "Bob", null, "Charlie")
// Вместо цепочки ?: лучше отфильтровать
val nonNull = list.filterNotNull() // ["Alice", "Bob", "Charlie"]
Оператор Элвиса — мощный инструмент, но не злоупотребляйте им. Иногда явный if-else или when делает код понятнее для других разработчиков.