Properties, lazy & lateinit Interview Questions
KOTLIN › Language Idioms
Walk me through how you'd decide between lazy and lateinit for a property that depends on Android's lifecycle, e.g. a view binding or an injected dependency.
What a strong answer covers: A strong answer keys off two things: whether the property is a val or needs reassignment, and whether initialization needs a computed block versus simple external assignment. Fragment view bindings typically use a nullable var, not lateinit-of-non-null, because the view can be destroyed and recreated while the Fragment instance survives, whereas a DI-injected non-null dependency set once by the framework is a textbook lateinit var, and by lazy fits values computed once from something already available at property-declaration time.
You've inherited a codebase littered with lateinit vars that occasionally crash with UninitializedPropertyAccessException in production. How would you triage and fix this systemically?
What a strong answer covers: A strong answer starts by checking ::prop.isInitialized at the actual read sites to confirm the crash is really an ordering or lifecycle bug rather than a genuine logic error, then traces why the assumed initialization point didn't run first, which on Android is often a lifecycle mismatch, like reading in a callback that can fire before the expected lifecycle method. The systemic fix is usually converting to a nullable property with explicit handling, lazy if it can be computed on first access, or dependency injection that guarantees the value exists before the object is usable, rather than sprinkling isInitialized checks everywhere.
Why might overusing by lazy on Android actually introduce subtle bugs or memory issues, e.g. in Fragments across configuration changes, and what would you watch for?
What a strong answer covers: The lazy delegate caches its value for the lifetime of the containing object, so if a Fragment or Activity lazily initializes something that captures a Context, View, or the component's own this, and that instance survives longer than expected, the cached value keeps that reference alive too and causes a leak. A strong answer also flags that the default SYNCHRONIZED mode adds locking overhead on every subsequent read even though it's only needed once, so on a hot, single-threaded path LazyThreadSafetyMode.NONE or PUBLICATION may be a better fit.