Прямые ссылки на публичные уроки для быстрого старта и стабильной индексации lesson-страниц.
Exceptions (исключения) описывают проблему, если в программе что-то пошло не так — как правило, их можно увидеть в логах. NullPointerException — ошибка, возникающая при обращении к неинициализированному объекту. Сокращённо — NPE.
null — ключевое слово, обозначающее отсутствие объекта. Программа падает, когда при обращении к переменной в ней оказывается null без какой-либо обработки.
Рассмотрим типичный сценарий. В приложении есть экран с контактами пользователей. Класс Contact содержит поля: Имя, Номер телефона, Место работы. Данные приходят из сети в формате JSON и парсятся в объекты класса Contact.
Если сервер для одного из контактов прислал null в поле «Место работы», а в модели ожидается обычная строка — приложение упадёт с ошибкой NullPointerException. Это классический пример того, почему нужна защита от null.
В Kotlin существуют nullable-типы — переменные, которые могут хранить либо значение, либо null. В отличие от обычных типов, где null недопустим, nullable-тип явно сигнализирует: «здесь может быть пусто».
Null нельзя присвоить переменной необнуляемого типа — в языке жёсткое разделение между обычными и обнуляемыми типами. Nullable-тип обозначается знаком ? после имени типа:
val nullableString: String? = null val nonNullableString: String = "some string"
Null также используется при инициализации переменной, если значение должно прийти позже по ходу работы программы.
При обращении к свойствам или методам nullable-переменной напрямую код не скомпилируется — Kotlin предупреждает о возможном null ещё на этапе разработки:
println(nullableString.length) // ошибка компиляции
Необходимо использовать оператор безопасного вызова ?.:
println(nullableString?.length)
Оператор проверяет значение слева на null: если оно не null — выполняет код, если null — ничего не происходит (без NPE). По сути это сокращённый if без ветки else. Развёрнутый эквивалент:
if (nullableString != null) { println(nullableString.length) } else { println("Переменная хранит null") }
Тип возвращаемого значения функции readLine() — String?, поэтому переменная для её результата тоже должна быть nullable, и все дальнейшие обращения к ней — безопасными.
При использовании оператора ?. результат может быть null, поэтому сохранить его в необнуляемую переменную нельзя:
val length: Int = nullableString?.length // ошибка
Если по условиям программы null в переменной недопустим, используется оператор «элвис» ?:. Если значение слева равно null, возвращается значение справа:
val length: Int = nullableString?.length ?: 0
Пример с readLine():
val someString: String = readLine() ?: ""
Название оператора происходит от сходства с эмодзи Элвис.
Оператор !! преобразует nullable-тип в обычный без какой-либо проверки. Если в переменной окажется null — программа выбросит NullPointerException:
val nullableString: String? = null val length: Int = nullableString!!.length // NPE при запуске
В продуктовой разработке !! следует применять крайне осторожно и только там, где есть обоснованная уверенность, что null не придёт — иначе мы сознательно отказываемся от защиты и подвергаем программу риску падения.