NullPointerException в Kotlin
В Kotlin обычные типы не бывают null, и большинство ошибок с пустыми значениями компилятор ловит ещё до запуска. Если программа всё же упала с NullPointerException, сначала найдите строку с ошибкой, а потом по ней — свою причину: почти всегда это одна из четырёх.
Как найти строку с ошибкой
Сообщение выглядит так:
Exception in thread "main" java.lang.NullPointerException
at MainKt.main(Main.kt:3)Под первой строкой сообщения идёт стек вызовов — строки at …: через какие функции прошла программа до ошибки. Нужна первая строка, где упомянут ваш файл. Main.kt:3 — файл и строка. MainKt — имя, под которым Kotlin собирает функции из файла Main.kt. В IntelliJ IDEA имя файла в окне Run — ссылка: щелчок переносит прямо на строку.
Причины и что делать
По этой строке и тексту сообщения выберите свой случай.
В строке есть !!замените его безопасным вариантом
Такая программа падает как раз с сообщением выше — на строке 3:
fun main() {
val name: String? = null
println(name!!.length)
}!! значит «здесь точно не null». Если значение всё-таки null, программа падает. Замените !! безопасным вариантом:
fun main() {
val name: String? = null
println(name?.length ?: 0)
if (name != null) {
println(name.length)
}
}0Все способы — в уроке Null-безопасность.
Значение пришло из кода на Javaпроверьте его на null
Библиотеки на Java не сообщают Kotlin, может ли их функция вернуть null. Тип такого значения IntelliJ IDEA показывает со знаком ! — например, String! — это платформенный тип: компилятор разрешает работать с ним как угодно, а проверка ложится на программиста. Если функция Java вернула null, а код Kotlin обратился к нему, будет NullPointerException.
Решение — сразу положить результат в переменную с явным типом со знаком ? и проверить:
fun main() {
val home: String? = System.getenv("NO_SUCH_VARIABLE_123")
println(home ?: "not set")
}not setSystem.getenv из Java возвращает null, если такой переменной окружения нет.
Сообщение про lateinitсвойство прочитано раньше времени
Свойство с lateinit прочитали раньше, чем присвоили. Ошибка тут другая, но похожая:
kotlin.UninitializedPropertyAccessException: lateinit property name has not been initializedКак с этим работать — в справке lateinit — отложенная инициализация.
Свойство читается из initпорядок создания объекта
Свойства класса получают значения сверху вниз. Если метод, вызванный из init или из конструктора родителя, обращается к свойству, которое ещё не получило значения, оно может оказаться null даже с типом без вопроса. Чаще всего это вызов open-метода из конструктора родительского класса. Не вызывайте из init методы, которые переопределяют наследники.
Если программа на Android
В Android то же сообщение появляется в окне Logcat Android Studio, строка с ошибкой ищется так же — по имени своего файла в строках at. Частые причины там — !! у значений, которые приходят из системы, и lateinit, прочитанный раньше, чем экран успел его заполнить.