ПрограммированиеAndroid разработчик

Что такое оператор Elvis (?:) в Kotlin, как и зачем его использовать? Какие нюансы и подводные камни могут возникнуть при его применении?

Проходите собеседования с ИИ помощником Hintsage

Ответ.

История вопроса:

Оператор Elvis (?:) появился в Kotlin как лаконичный и безопасный способ обработки nullable-значений. Он получил своё название из-за схожести с причёской Элвиса Пресли, если смотреть на оператор сбоку. Цель — избавиться от шаблонного кода вида if (a != null) a else b и сделать повседневную разработку более удобной.

Проблема:

Прямое обращение к значению, которое может быть null, приводит к ошибке времени выполнения (NullPointerException). Поэтому необходим инструмент, позволяющий элегантно подставлять значения по умолчанию, когда переменная оказывается null.

Решение:

Elvis-оператор применим к nullable-типам. Если выражение слева от оператора не равно null, возвращается оно, иначе — выражение справа. Это делает код более компактным и безопасным.

Пример кода:

fun getLength(str: String?): Int { return str?.length ?: 0 } val result = getLength(null) // result == 0 val result2 = getLength("Hello") // result2 == 5

Ключевые особенности:

  • Позволяет избегать явных проверок на null
  • Может использоваться для выбрасывания исключений
  • Идеально сочетается с nullable-типами, выражениями и функциями с побочными эффектами

Вопросы с подвохом.

Что будет, если справа от Elvis-оператора выражение с побочным эффектом? Срабатывает оно всегда?

Нет! Выражение справа вычисляется только если слева оказался null. Это может играть важную роль, если функция имеет побочные эффекты или "дорогостоящие" вычисления.

Пример кода:

var called = false val x: String? = "test" val y = x ?: run { called = true; "default" } // called будет равен false, потому что run даже не выполнится

Можно ли использовать Elvis-оператор для выбрасывания исключений?

Да, в Kotlin можно писать так:

fun getLengthStrict(str: String?): Int = str?.length ?: throw IllegalArgumentException("str is null")

Если str равен null, будет выброшено исключение. Это удобный механизм валидации данных.

Можно ли "склеивать" несколько Elvis-операторов подряд?

Да, это обычный подход для fallback'ов:

val name = fromDatabase ?: fromCache ?: "Unknown"

Это выражение вернёт первое НЕ null значение или строку "Unknown".

Типовые ошибки и анти-паттерны

  • Сложные длинные цепочки Elvis-операторов, затрудняющие чтение кода
  • Игнорирование побочных эффектов выражения справа, что может вести к неожиданному поведению
  • Использование Elvis, когда нужно явно проверить значение на null и обработать разными способами

Пример из жизни

Негативный кейс

Многоуровневая вложенность null-check через Elvis:

val title = a?.b?.c?.d?.e ?: defaultTitle

Плюсы:

  • Кратко для простой логики

Минусы:

  • Плохо читается
  • Сложно отлаживать, если проблема неясна

Позитивный кейс

Явная декомпозиция по шагам, понятные имена переменных:

val deepValue = a?.b val deeperValue = deepValue?.c?.d ?: default

Плюсы:

  • Повышена читаемость
  • Проще добавить дополнительные проверки или лог

Минусы:

  • Чуть более многословно; для новичков может казаться "лишними" шагами