Оператор !!: когда и почему его следует избегать
Разберитесь в операторе утверждения ненулевого значения, его рисках и лучших альтернативах.
«Оператор !!: когда и почему его следует избегать» — бесплатный урок 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 — локальная установка не требуется.
Все уроки этого курса
- Типы, допускающие null, и модификатор ?
- Безопасный вызов ?. и Elvis ?: в реальном коде
- let, also и run с получателями, допускающими null
- Оператор !!: когда и почему его следует избегать