In Kotlin, ci sono due approcci diversi per l'inizializzazione ritardata delle proprietà: lateinit e lazy.
lateinit — un modificatore applicato a variabili (var) che verranno inizializzate in seguito, di solito tramite DI o in un blocco di inizializzazione. Si applica solo a variabili non statiche di tipologie NON nullable. Accedere prima dell'inizializzazione genera un'eccezione UninitializedPropertyAccessException.
class MyClass { lateinit var data: String fun init() { data = "Hello!" } }
lazy — un delegato speciale applicato a proprietà val (solo read-only). L'espressione di inizializzazione viene calcolata al primo accesso alla variabile. Sicuro per l'accesso multithread di default.
val config: Config by lazy { loadConfigFromFile() }
lateinit non funziona con i tipi primitivi e con val.lazy non consente la reinizializzazione.lateinit è per variabili che saranno sicuramente assegnate in seguito (ad esempio, tramite un framework DI o nel ciclo di vita di un fragment Android).lazy è per calcoli ritardati, quando il valore è costoso in termini di calcolo e potrebbe non essere richiesto.È possibile utilizzare
lateinitper proprietà di tipo Int?
Risposta: No. lateinit funziona solo con tipos oggettivi NON nullable. Per i primitivi e i tipi nullable, non è possibile. Tentare di dichiarare lateinit var a: Int genererà un errore di compilazione.
Storia
In un progetto educativo hanno dichiarato una variabile di configurazione come lateinit var config: Config?, ma il compilatore non ha permesso di farlo — hanno risparmiato tempo, ma hanno dovuto capire perché non funzionava come previsto.
Storia
In un'app Android hanno dimenticato di controllare se la proprietà lateinit fosse stata inizializzata prima della chiamata. Questo ha portato a un crash dell'app in produzione — il designer ha tentato di accedere alla proprietà prima di onCreateView. Sono stati necessari controlli aggiuntivi.
Storia
Quando si utilizza il multithreading, lo sviluppatore ha applicato by lazy per inizializzare un oggetto costoso senza passare un parametro, pensando che il delegato di default non fosse thread-safe. Di conseguenza, nella release sono sorti problemi di race condition. Si è risolto passando il parametro appropriato per lazy: by lazy(LazyThreadSafetyMode.SYNCHRONIZED) { ... }.