ПрограммированиеAndroid разработчик

Как работает late-initialized property ('lateinit var') в Kotlin, чем отличается от nullable-свойств и в каких ситуациях его стоит использовать?

Проходите собеседования с ИИ помощником Hintsage

Ответ

История вопроса

Kotlin ориентируется на безопасность типов и избегание null-указателей, но часто возникает задача отложенной (late) инициализации переменных, например, при использовании dependency injection или в Android Activity. Для этого добавлен модификатор lateinit.

Проблема

Обычные свойства требуют обязательной инициализации или должны быть nullable, что неудобно, если гарантируется поздняя, но обязательная инициализация. Использование nullable-типа усложняет код и требует дополнительных null-проверок.

Решение

lateinit позволяет создать неинициализированное до поры свойство, но обещать компилятору, что оно будет инициализировано до первого использования. Инициировать можно не в конструкторе, а позже.

class UserViewModel { lateinit var repository: UserRepository fun onCreate() { repository = UserRepository() } fun getData() = repository.load() }

Ключевые особенности:

  • Позволяет не использовать null и при этом отложить инициализацию
  • throw UninitializedPropertyAccessException при обращении к неинициализированному lateinit свойству
  • Только для var и не для примитивных типов (Int, Double etc.)

Вопросы с подвохом.

Можно ли применять lateinit для свойств val?

Нет. lateinit работает только с var, так как val должен быть инициализирован один раз немедленно либо через геттер.

Работает ли lateinit с типами Int, Boolean, Double и прочими примитивами?

Нет. Только с объектными ссылочными типами. Для примитивов используйте nullable-типы.

Что произойдет, если обратиться к lateinit свойству до инициализации?

Kotlin бросит UninitializedPropertyAccessException:

lateinit var foo: String println(foo) // Exception

Типовые ошибки и анти-паттерны

  • Забыл инициализировать lateinit свойство — приложение упадёт
  • Использование там, где нужна nullable семантика с проверкой isInitialized
  • Применение для примитивных типов и val

Пример из жизни

Негативный кейс

Разработчик объявил lateinit var item: String, не инициализировал до первого вызова метода getItem. Итог: падение приложения.

Плюсы:

  • Избавляет от nullable, если все инициализировано корректно

Минусы:

  • Риск перепутать жизненный цикл и получить runtime-исключение

Позитивный кейс

Android Activity: lateinit var presenter, инициализация в onCreate. Использование presenter во всех жизненных методах безопасно: nullability не нужен.

Плюсы:

  • Повышает читаемость, избегает лишних проверок
  • Гарантирует обязательную инициализацию

Минусы:

  • Необходимость явно следить за порядком вызова инициализации