ProgrammingAndroid Developer

What are 'lateinit' and 'lazy' in Kotlin? Explain the differences, nuances of usage, limitations, and provide corresponding code examples.

Pass interviews with Hintsage AI assistant

Answer

In Kotlin, there are two different approaches for late initialization of properties: lateinit and lazy.

lateinit is a modifier applied to variables (var) that will be initialized later, usually through DI or in an initialization block. It is suitable only for non-static variables of NON-nullable types. Accessing it before initialization throws an UninitializedPropertyAccessException.

class MyClass { lateinit var data: String fun init() { data = "Hello!" } }

lazy is a special delegate applied to val properties (read-only only). The initializer expression is evaluated on the first access to the variable. It is safe for multi-threaded access by default.

val config: Config by lazy { loadConfigFromFile() }
  • lateinit does not work with primitive types and val.
  • lazy does not allow re-initialization.
  • lateinit is for variables that are guaranteed to be assigned later (for example, via a DI framework or during an Android lifecycle fragment).
  • lazy is for lazy calculations when the value is costly to compute and may not be required.

Trick Question

Can lateinit be used for properties of type Int?

Answer: No. lateinit works only with object NON-nullable types. It cannot be used for primitives and nullable types. Attempting to declare lateinit var a: Int will result in a compilation error.

Examples of real mistakes due to lack of understanding of the nuances of the topic


Story

In an educational project, they declared a configuration variable as lateinit var config: Config?, but the compiler did not allow this — they saved time but had to figure out why it did not work as expected.


Story

In an Android application, they forgot to check for initialization of the lateinit property before calling it. This led to a crash in production — the designer tried to access the property before onCreateView. Additional checks helped.


Story

When using multi-threading, a developer applied by lazy for initializing a resource-intensive object without passing a parameter, thinking that the default delegate is not thread-safe. As a result, there were race condition issues in the release. They resolved this by passing the appropriate parameter for lazy: by lazy(LazyThreadSafetyMode.SYNCHRONIZED) { ... }.