Why Deferred Intilization?
First, initialization must be delayed due to a temporal mismatch. This occurs when a non-nullable property cannot be assigned a value within a class's constructor because its value is provided later by an external system, such as Android framework views or a dependency injection framework like Dagger. If developers were to use nullable types to address this, it would necessitate frequent and often redundant null checks (?.) throughout the codebase, diminishing Kotlin's null-safety benefits and increasing the risk of runtime NullPointerExceptions if checks are omitted.
Second, deferred initialization enhances efficiency by postponing the creation of resources that are computationally expensive or might not be used at all during the application's runtime. By delaying the allocation and setup of such resources until the moment they are actually accessed, the application can improve its startup performance, conserve memory, and overall reduce unnecessary overhead. This ensures that the cost of initialization is only incurred when it is strictly required, leading to a more responsive and optimized user experience.
Two primary ways for Kotlin deferred initialization are lateinit and lazy initialization. These help avoid unnecessary computation or uninitialized property errors by allowing to delay when a variable actually gets its value.
Lateinit in Kotlin
What it is: The lateinit modifier allows to declare a non-null var without initializing it immediately.
Why it's important: It’s useful when the value of a property is not available at the time of declaration but will definitely be initialized before use — such as in dependency injection, unit tests, or Android components.
What happens if not used: Without lateinit, either make the variable nullable (and check for null every time), or initialize it with a dummy value, which can be unsafe or misleading.
Main Features:
- Only works with
var(mutable) and non-nullable types - Can’t be used with primitive types (e.g.,
Int,Double) - Accessing it before initialization throws
UninitializedPropertyAccessException
Example:
class MyClass {
lateinit var name: String
fun initialize() {
name = "Robotics"
}
fun printName() {
println(name)
}
}
fun main() {
val obj = MyClass()
obj.initialize()
obj.printName() // Prints: Robotics
}
Lazy Initialization in Kotlin
What it is: The lazy function allows to declare a read-only val whose value is computed and stored only upon first access.
Why it's important: It's ideal when the initialization of a property is expensive (e.g., loading data, heavy computation) and may not be needed unless the property is actually used.
What happens if not used: Without lazy, the object might be initialized even if never used, wasting resources or slowing startup time.
Main Features:
- Only works with
val(read-only) properties - Thread-safe by default (using
LazyThreadSafetyMode.SYNCHRONIZED) - The value is cached after first initialization and reused on future accesses
Example:
val data: String by lazy {
println("Computing value...")
"Robophysics Data"
}
fun main() {
println("Before accessing data")
println(data) // Triggers initialization
println(data) // Uses cached value
}