← Назад к вопросам

Что такое !!?

1.6 Junior🔥 161 комментариев
#Kotlin основы

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Оператор !! в Kotlin: принудительное разыменование nullable-типа

Оператор !! (произносится как "два восклицательных знака" или "bang-bang") в Kotlin — это оператор утверждения не-null значения (not-null assertion operator). Он используется для принудительного преобразования значения nullable-типа (обозначаемого ?) в соответствующий non-null тип, явно заявляя: "Я уверен, что в данный момент это значение не равно null".

Основная механика работы

Когда вы применяете !! к nullable-переменной, компилятор Kotlin "снимает" вопросительный знак и начинает работать с типом как с обычным, не допускающим null. Однако если во время выполнения программы значение переменной всё же окажется null, будет немедленно выброшено исключение KotlinNullPointerException (Kotlin NPE).

fun main() {
    val nullableString: String? = "Hello"
    val nonNullString: String = nullableString!! // Успешно: nullableString не null
    println(nonNullString.length) // Работает, выводит 5

    val anotherNullable: String? = null
    val willCrash: String = anotherNullable!! // Выбрасывает KotlinNullPointerException!
    println(willCrash) // Эта строка не выполнится
}

Сценарии использования и предостережения

!! следует использовать крайне осторожно и считать "красным флагом" в коде. Его применение часто указывает на недостаточную обработку nullable-состояний. Вот основные случаи, где он может встречаться:

  • Интеграция с Java-кодом, где аннотации @Nullable/@NotNull отсутствуют или некорректны, и разработчик на основе знания кода утверждает, что значение не может быть null.
  • Инициализация lateinit переменных, доступ к которым до инициализации также вызовет исключение (но другое — UninitializedPropertyAccessException). lateinit зачастую является более чистым выбором, если null не является допустимым состоянием.
  • Взаимодействие с фреймворками, которые гарантируют инициализацию к моменту использования (например, поля View в Android после вызова onCreateView). Однако даже здесь предпочтительнее использовать lateinit или делегат by viewModels()/by viewBinding().

Почему от !! стоит уходить: безопасные альтернативы

Система типов Kotlin с null-безопасностью — одна из его ключевых фишек, призванная избавить от NPE. Оператор !! обходит эту систему. Вместо него используйте:

  1. Безопасный вызов (Safe Call) ?.

    val length: Int? = nullableString?.length // Если null, вернет null
    
  2. Оператор Элвиса (Elvis Operator) ?:

    val length: Int = nullableString?.length ?: 0 // Если null, вернет 0
    val lengthOrCrash: Int = nullableString?.length ?: error("String was null") // Явная ошибка с понятным сообщением
    
  3. Умное приведение (Smart Cast) и явные проверки

    if (nullableString != null) {
        val length = nullableString.length // Внутри блока компилятор сам приводит тип к String
    }
    
  4. Функция requireNotNull() или checkNotNull() (для валидации аргументов или состояний)

    fun processString(str: String?) {
        val nonNullStr = requireNotNull(str) { "Аргумент 'str' не может быть null" }
        // Далее работаем с nonNullStr как с String
    }
    

Итог

!! — это оператор, который преобразует nullable-тип в non-null тип, обещая компилятору, что значение не является null. Если это обещание нарушается во время выполнения, программа завершается с KotlinNullPointerException. Хотя у него есть узкие оправданные случаи применения, в современной Kotlin-разработке он считается антипаттерном. Его наличие в коде обычно сигнализирует о том, что null-безопасность языка была проигнорирована, и следует искать более безопасные конструкции, такие как безопасные вызовы, оператор Элвиса или умные приведения, чтобы сделать код стабильным и предсказуемым.