0Pricing
Kotlin Academy · Урок

Оператор !!: когда и почему его следует избегать

Разберитесь в операторе утверждения ненулевого значения, его рисках и лучших альтернативах.

«Оператор !!: когда и почему его следует избегать» — бесплатный урок Kotlin Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Kotlin Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Kotlin Academy содержит 4 уроков всего.

Что такое !!?

Оператор утверждения о ненулевом значении !! преобразует тип, допускающий null, в тип, не допускающий null. Если во время выполнения значение равно null, вызывается NullPointerException.

Базовое использование !!

x!! возвращает x, если оно не равно null, а в противном случае вызывает NPE.

fun main() {
    val name: String? = "Kotlin"
    val len: Int = name!!.length // 6
    println(len)
}

!! вызывает исключение при null

Если значение действительно равно null, Вы получите именно то исключение, которое Kotlin пытается предотвратить.

fun main() {
    val name: String? = null
    try {
        println(name!!.length)
    } catch (e: NullPointerException) {
        println("NPE caught!")
    }
}

Лучше: безопасный вызов

Вместо !! отдавайте предпочтение ?. — это обеспечивает корректную обработку без сбоев.

fun main() {
    val name: String? = null
    val len = name?.length
    println(len) // null — no crash
}

Лучше: оператор Элвиса

Объединяйте ?. с ?:, чтобы предоставить разумное значение по умолчанию.

fun main() {
    val name: String? = null
    val len = name?.length ?: 0
    println(len) // 0
}

Лучше: умное приведение типа

Проверка if (x != null) включает умное приведение типа, поэтому !! не требуется.

fun main() {
    val name: String? = "Alice"
    if (name != null) {
        println(name.length) // smart-cast to String
    }
}

Лучше: requireNotNull

Если значение обязательно должно присутствовать, requireNotNull(x) { "..." } вызывает содержательное исключение IllegalArgumentException.

fun process(name: String?) {
    val safe = requireNotNull(name) { "name is required" }
    println("processing $safe")
}
fun main() {
    process("Ada")
    // process(null) // throws IllegalArgumentException: name is required
}

Лучше: checkNotNull

checkNotNull(x) ведёт себя так же, но вызывает IllegalStateException — используйте его для инвариантов.

class Service {
    private var data: String? = null
    fun load() { data = "loaded" }
    fun read(): String = checkNotNull(data) { "load() must be called first" }
}
fun main() {
    val s = Service()
    s.load()
    println(s.read())
}

Допустимые случаи использования !!

Редкий, но допустимый случай: отсутствие null действительно является инвариантом, который невозможно доказать на этапе компиляции (например, после вызова через механизм отражения). Добавьте комментарий с объяснением причины.

fun main() {
    val list = listOf(1, 2, 3)
    val firstEven: Int = list.find { it % 2 == 0 }!! // safe: we know list has an even
    println(firstEven)
}

Цепочка !! — абсолютный антишаблон

Несколько !! в цепочке — признак проблемного кода. Перепишите его с использованием безопасных вызовов и защитных условий.

class A(val b: B?)
class B(val c: C?)
class C(val name: String?)
fun main() {
    val a: A? = A(B(C("ok")))
    // BAD: val n = a!!.b!!.c!!.name!!
    val n = a?.b?.c?.name ?: "unknown"
    println(n)
}

Удаление !! при рефакторинге

Заменяйте !! более честным API: возвращаемыми значениями, допускающими null, вызовом requireNotNull в точке входа или досрочным возвратом.

fun firstUpper(s: String?): String? = s?.firstOrNull()?.uppercase()
fun main() {
    println(firstUpper("alice")) // A
    println(firstUpper(""))      // null
    println(firstUpper(null))    // null
}

Быстрая проверка

Что произойдёт, если применить !! к значению, которое во время выполнения действительно равно null?

Итоги

!! — обходной путь, отключающий безопасность null в Kotlin. Отдавайте предпочтение ?., ?:, умным приведениям типов, requireNotNull или checkNotNull. Используйте !! только для документированных инвариантов, которые компилятор не может доказать.

Часто задаваемые вопросы

Урок «Оператор !!: когда и почему его следует избегать» бесплатный?

Да — полный текст урока «Оператор !!: когда и почему его следует избегать» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Kotlin Academy, подпишись на CoddyKit PRO. Курс Kotlin Academy содержит 4 уроков всего.

Чему я научусь в уроке «Оператор !!: когда и почему его следует избегать»?

Разберитесь в операторе утверждения ненулевого значения, его рисках и лучших альтернативах. Ты практикуешь Kotlin Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Kotlin Academy?

Предыдущий опыт не требуется. Kotlin Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.

Сколько времени занимает урок «Оператор !!: когда и почему его следует избегать»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Kotlin Academy?

Да. Каждый урок Kotlin Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Типы, допускающие null, и модификатор ?
  2. Безопасный вызов ?. и Elvis ?: в реальном коде
  3. let, also и run с получателями, допускающими null
  4. Оператор !!: когда и почему его следует избегать
← Назад к Kotlin Academy