Оператор безопасного вызова '?.' является одним из ключевых инструментов для борьбы с null-значениями в Kotlin и появился как развитие идей языка, ориентированного на повышение безопасности и удобства работы с потенциально отсутствующими значениями.
История вопроса: В Java null-значения часто становятся источником ошибок (NullPointerException). Kotlin ввёл строгую систему типов с явным выделением nullable и not-nullable переменных и сопроводил это появлением инструментов для их удобного использования.
Проблема: Как избежать NullPointerException при работе с объектами, которые могут быть null, при этом не жертвуя читаемостью и лаконичностью кода?
Решение: Оператор '?.' позволяет деликатно обращаться к свойствам и методам nullable-переменных: если объект не null, выполняется вызов, если null — возвращается null (или необходимая логика дальше).
Пример кода:
val user: User? = getUser() val name = user?.name // если user != null, вернётся user.name, иначе null user?.printInfo() // если user != null, вызовется printInfo()
Ключевые особенности:
Может ли safe call operator '?.' использоваться слева от присваивания?
Нет. Оператор '?.' нельзя использовать для безопасной установки значения свойства или переменной; он применяется только для доступа или вызова. Следующее некорректно:
user?.name = "Alex" // Ошибка компиляции
Присваивание свойств можно безопасно проводить через явную проверку:
user?.let { it.name = "Alex" }
Что возвращает цепочка safe call операторов при первой встрече с null?
Как только один из элементов цепочки '?.' равен null, результат выражения становится null, дальнейшие safe call-ы не выполняются.
Пример:
user?.address?.zipCode // если user или address == null, результат null
Можно ли использовать safe call '?.' с функциями, которые возвращают Unit?
Да, вызов все равно произойдет только если объект не null, а вернется null вместо Unit если объект null.
Пример:
user?.clearData() // если user == null, ничего не произойдет
Разработчик применяет '!!' там, где объект мог быть null, после длинной цепочки safe call:
val country = user?.address?.city?.country!!
Плюсы:
Минусы:
Используется safe call совместно с Elvis-оператором для возврата дефолтного значения:
val country = user?.address?.city?.country ?: "Unknown"
Плюсы:
Минусы: