programowanieProgramista Android

Jak działa właściwość z późną inicjalizacją ('lateinit var') w Kotlinie, czym różni się od właściwości nullable i w jakich sytuacjach warto ją stosować?

Zdaj rozmowy kwalifikacyjne z asystentem AI Hintsage

Odpowiedź

Historia pytania

Kotlin skupia się na bezpieczeństwie typów i unikaniu wskaźników null, ale często pojawia się potrzeba opóźnionej (late) inicjalizacji zmiennych, na przykład podczas używania wstrzykiwania zależności (dependency injection) lub w Android Activity. Dlatego dodano modyfikator lateinit.

Problem

Zwykłe właściwości wymagają obowiązkowej inicjalizacji lub muszą być nullable, co jest niewygodne, jeśli gwarantowana jest późna, ale obowiązkowa inicjalizacja. Użycie typu nullable komplikuje kod i wymaga dodatkowych sprawdzeń null.

Rozwiązanie

lateinit pozwala stworzyć nieinicjalizowaną do czasu właściwość, ale obiecuje kompilatorowi, że zostanie ona zainicjalizowana przed pierwszym użyciem. Inicjować można nie w konstruktorze, a później.

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

Kluczowe cechy:

  • Umożliwia nieużywanie null i jednoczesne opóźnienie inicjalizacji
  • throw UninitializedPropertyAccessException przy próbie dostępu do nieinicjalizowanej właściwości lateinit
  • Tylko dla var i nie dla typów prymitywnych (Int, Double itd.)

Pytania z pułapką.

Czy można stosować lateinit dla właściwości val?

Nie. lateinit działa tylko z var, ponieważ val musi być zainicjalizowany raz natychmiast lub przez getter.

Czy lateinit działa z typami Int, Boolean, Double i innymi prymitywami?

Nie. Tylko z typami referencyjnymi. Dla prymitywów użyj typów nullable.

Co się stanie, jeśli odwołasz się do właściwości lateinit przed inicjalizacją?

Kotlin wyrzuci UninitializedPropertyAccessException:

lateinit var foo: String println(foo) // Wyjątek

Typowe błędy i antywzorce

  • Zapomniano zainicjalizować właściwość lateinit — aplikacja się zawiesi
  • Użycie tam, gdzie potrzebna jest semantyka nullable z sprawdzaniem isInitialized
  • Stosowanie dla typów prymitywnych i val

Przykład z życia

Negatywny przypadek

Programista zadeklarował lateinit var item: String, nie zainicjalizował go przed pierwszym wywołaniem metody getItem. Efekt: zawieszenie aplikacji.

Zalety:

  • Pozbywa się nullable, jeśli wszystko jest poprawnie zainicjalizowane

Wady:

  • Ryzyko pomylenia cyklu życia i uzyskania wyjątku w czasie wykonywania

Pozytywny przypadek

Android Activity: lateinit var presenter, inicjalizacja w onCreate. Użycie presenter we wszystkich metodach cyklu życia jest bezpieczne: nie potrzebna jest nullowalność.

Zalety:

  • Zwiększa czytelność, unika zbędnych sprawdzeń
  • Gwarantuje obowiązkową inicjalizację

Wady:

  • Konieczność wyraźnego śledzenia kolejności wywołań inicjalizacji