W Kotlinie istnieją dwa różne podejścia do późnej inicjalizacji właściwości: lateinit i lazy.
lateinit — modyfikator stosowany do zmiennych (var), które będą inicjalizowane później, zazwyczaj przez DI lub w bloku inicjalizacyjnym. Nadaje się tylko dla niestatycznych zmiennych typu NIE nullable. Odwołanie przed inicjalizacją — wyrzuca wyjątek UninitializedPropertyAccessException.
class MyClass { lateinit var data: String fun init() { data = "Hello!" } }
lazy — specjalny delegat stosowany do właściwości val (tylko do odczytu). Wyrażenie inicjalizujące jest obliczane przy pierwszym odwołaniu do zmiennej. Domyślnie bezpieczne dla dostępu wielowątkowego.
val config: Config by lazy { loadConfigFromFile() }
lateinit nie działa z typami prymitywnymi i val.lazy nie dopuszcza ponownej inicjalizacji.lateinit — dla zmiennych, które na pewno będą przypisane później (na przykład przez framework DI lub w cyklu życia fragmentu Androida).lazy — dla leniwych obliczeń, gdy wartość jest kosztowna w obliczeniach i może nie być konieczna.Czy można używać
lateinitdla właściwości typu Int?
Odpowiedź: Nie. lateinit działa tylko z obiektowymi typami NIE nullable. Dla typów prymitywnych i nullable — nie można. Próba zadeklarowania lateinit var a: Int spowoduje błąd kompilacji.
Historia
W projekcie edukacyjnym zadeklarowano zmienną konfiguracyjną jako lateinit var config: Config?, ale kompilator nie pozwolił tego zrobić — zaoszczędzili czas, ale musieli się dowiedzieć, dlaczego to nie działa tak, jak się spodziewali.
Historia
W aplikacji Android zapomniano sprawdzić inicjalizację właściwości lateinit przed wywołaniem. Doprowadziło to do awarii aplikacji w produkcji — projektant próbował uzyskać dostęp do właściwości przed onCreateView. Pomogły dodatkowe sprawdzenia.
Historia
Przy użyciu wielowątkowości programista zastosował by lazy do inicjalizacji zasobożernego obiektu bez przekazywania parametru, sądząc, że delegat domyślnie nie jest bezpieczny dla wątków. W rezultacie w wydaniu pojawiły się problemy z warunkami wyścigu. Rozwiązano to przez przekazanie odpowiedniego parametru do lazy: by lazy(LazyThreadSafetyMode.SYNCHRONIZED) { ... }.