Null-safety: nullable-типы и оператор ?.
Знакомимся с фирменной защитой Kotlin от «ошибки на миллиард долларов».
Null-safety — встроенная в систему типов Kotlin защита, разделяющая типы на те, что могут содержать
null(nullable), и те, что не могут.
Создатель null Тони Хоар назвал его «ошибкой на миллиард долларов»: обращение к null рушит программы. Kotlin решает проблему на уровне компилятора, не давая случайно вызвать метод у потенциально пустого значения.
Nullable и non-null типы
Обычный тип, например String, не может быть null. Чтобы разрешить null, к типу добавляют знак вопроса: String?.
fun main() {
val name: String = "Аня"
// val bad: String = null // ОШИБКА: тип не nullable
val maybe: String? = null // так можно
println(name)
println(maybe)
}Вывод:
Аня null
Безопасный вызов ?.
У nullable-значения нельзя просто вызвать метод — компилятор не пропустит. Оператор ?. вызывает метод, только если значение не null; иначе всё выражение возвращает null.
fun main() {
val name: String? = null
println(name?.length) // вернёт null, не упадёт
val city: String? = "Москва"
println(city?.uppercase())
}Вывод:
null МОСКВА
Цепочки безопасных вызовов
Операторы ?. можно соединять в цепочку. Если любое звено окажется null, вся цепочка вернёт null, не выбросив исключение.
data class Address(val city: String?)
data class User(val address: Address?)
fun main() {
val user: User? = User(Address(null))
println(user?.address?.city?.length)
}Вывод:
null
Как работает под капотом
Знак ? — это не магия времени выполнения, а информация для компилятора. Он отслеживает, какие переменные могут быть null, и отказывается компилировать код, где у них без проверки вызывают методы. В байт-коде String и String? — это один и тот же тип; разница существует только на этапе компиляции и помогает поймать ошибку до запуска программы.
Частые ошибки
- Делать всё nullable «на всякий случай». Знак
?ставьте, только если значение действительно может отсутствовать. - Пытаться вызвать метод напрямую у
String?. Компилятор потребует?.или проверку наnull. - Забывать, что
?.возвращаетnull. Результат тоже nullable, и его, возможно, придётся обработать дальше.
Итог
- Типы делятся на non-null (
String) и nullable (String?). - Безопасный вызов
?.срабатывает только для не-nullзначения, иначе возвращаетnull. - Безопасные вызовы можно объединять в цепочку.
- Проверки работают на этапе компиляции и предотвращают
NullPointerException.