0
0
KotlinComparisonBeginner · 4 min read

Lateinit vs Lazy in Kotlin: Key Differences and Usage

In Kotlin, lateinit is used to declare a non-null variable that will be initialized later before use, mainly for mutable vars, while lazy is used for read-only properties that initialize once on first access. lateinit works only with var and non-primitive types, whereas lazy works with val and supports thread-safe initialization.
⚖️

Quick Comparison

Here is a quick side-by-side comparison of lateinit and lazy in Kotlin.

Factorlateinitlazy
Initialization timeMust be initialized before use manuallyInitialized automatically on first access
Variable typeOnly var (mutable), non-primitive typesOnly val (immutable), any type
Null safetyNon-null, throws exception if accessed before initInitialized lazily, never null after initialization
Thread safetyNo built-in thread safetySupports thread-safe lazy initialization by default
Use caseWhen you want to set a variable later (e.g., dependency injection)When initialization is expensive and should be delayed until needed
Syntaxlateinit varval by lazy { ... }
⚖️

Key Differences

lateinit is a modifier used with var properties to tell Kotlin that the variable will be initialized later before use. It is mainly used for non-null properties that cannot be initialized in the constructor or at declaration. If you try to access a lateinit variable before it is initialized, Kotlin throws an exception called UninitializedPropertyAccessException.

On the other hand, lazy is a delegate used with val properties to delay initialization until the first time the property is accessed. This is useful when the initialization is costly or depends on some runtime information. The lazy delegate also supports thread safety by default, making it safe to use in concurrent environments.

Another important difference is that lateinit cannot be used with primitive types like Int or Boolean, while lazy can be used with any type. Also, lateinit requires manual initialization, whereas lazy handles initialization automatically.

⚖️

Code Comparison

Here is how you use lateinit to declare and initialize a variable later:

kotlin
class Example {
    lateinit var text: String

    fun initialize() {
        text = "Hello, lateinit!"
    }

    fun printText() {
        if (::text.isInitialized) {
            println(text)
        } else {
            println("text is not initialized")
        }
    }
}

fun main() {
    val example = Example()
    example.printText()  // text is not initialized
    example.initialize()
    example.printText()  // Hello, lateinit!
}
Output
text is not initialized Hello, lateinit!
↔️

Lazy Equivalent

Here is how you use lazy to initialize a value only when it is first accessed:

kotlin
class Example {
    val text: String by lazy {
        println("Initializing lazy text")
        "Hello, lazy!"
    }

    fun printText() {
        println(text)
    }
}

fun main() {
    val example = Example()
    println("Before accessing text")
    example.printText()  // Triggers initialization
    example.printText()  // Uses cached value
}
Output
Before accessing text Initializing lazy text Hello, lazy! Hello, lazy!
🎯

When to Use Which

Choose lateinit when: you have a mutable property that cannot be initialized at declaration but will definitely be initialized before use, such as dependency injection or Android view binding.

Choose lazy when: you want an immutable property that should be initialized only once and only when needed, especially if the initialization is expensive or you want thread safety.

In short, use lateinit for mutable vars initialized later, and lazy for read-only vals initialized on first access.

Key Takeaways

lateinit is for mutable vars initialized manually before use.
lazy is for immutable vals initialized automatically on first access.
lateinit cannot be used with primitives; lazy can.
lazy supports thread-safe initialization by default.
Use lateinit for late initialization, lazy for delayed, on-demand initialization.