Kotlin: lateinit vs lazy

Kotlin: lateinit vs lazy

Differences between Kotlin's lateinit and lazy.


5 min read

If get to know something new by reading my articles, don't forget to endorse me on LinkedIn

This article introduces the concepts of lateinit and lazy in Kotlin, highlighting their popularity in handling property initialization. The article promises to explain the differences between these concepts, and their intended use cases and provides code samples to demonstrate their practical implementation. By the end of the article, readers are expected to have a comprehensive understanding of when to utilize these features in their Kotlin projects.

What is lateinit?

The lateinit keyword in Kotlin enables the declaration of non-nullable properties without immediate initialization. This is beneficial when dealing with properties that necessitate a context or extensive initialization that cannot be done during object creation. However, it is crucial to initialize lateinit properties before accessing them, as failing to do so will result in an UninitializedPropertyAccessException. Let's examine a code sample to better understand this concept.

class DemoClass{
    lateinit var userAge: UserAge

    fun init() {
        userAge = UserAge(27)

    fun printAge() {
        if (::age.isInitialized) {
            println("Age is : ${userAge.age}")
        } else {
            println("Age not initialized")

In the provided code snippet, a property called age is declared using the lateinit keyword. The init() function is responsible for initializing this property. The code then checks if the property has been initialized using the isInitialized property reference. If it is initialized, the value of age is printed; otherwise, a message indicating that it has not been initialized yet is displayed.

What is lazy?

Moving on to the concept of lazy allows for the creation of properties that are initialized lazily. This means that the property will only be computed and initialized when it is accessed for the first time. Subsequent accesses to the property will return the cached value. The differences between lateinit and lazy are illustrated in the following code segment.

class AnotherDemoClass{
    val age: UserAge by lazy {
        // Doing heavy work...

The code snippet showcases the usage of the lazy delegate in Kotlin. The property age is declared using the lazy delegate. The lambda expression provided to lazy represents the initialization logic, which is executed only when the property "expensiveProperty" is accessed for the first time. In this case, the computed value is set to 27. Upon subsequent access, the cached value is returned, preventing redundant computations.

Differences b/ lateinit and lazy and their Use Cases

Initialization Time:

The main difference between lateinit and lazy in Kotlin is the timing of initialization. lateinit allows for delaying the initialization of a property until a later point, while lazy initialize the property only when it is first accessed.

lateinit is useful when working with properties that require a context or heavy initialization that cannot be performed during object creation. It provides flexibility by deferring the initialization to a more suitable time, such as within a specific method or initialization block. This can enhance performance by avoiding unnecessary computations or initializations until they are needed.

On the other hand, lazy initialization is beneficial when dealing with properties that are computationally expensive to initialize but may not be needed throughout the object's entire lifespan. By lazily initializing such properties, the overhead of unnecessary computations can be avoided, and the initialization can be postponed until the property is accessed. This approach can optimize resource usage and improve overall application efficiency.

Nullable vs Non-Nullable:

A significant distinction between lateinit and lazy in Kotlin pertains to the nullability of properties. latest properties must be declared as non-nullable, meaning they cannot hold null values. This requirement arises from the expectation that lateinit properties will be initialized before accessing them, and accessing an uninitialized lateinit property results in a UninitializedPropertyAccessException.

In contrast, lazy properties can be either nullable or non-nullable. This is because lazy properties are only initialized when they are first accessed, and if they are never accessed, they remain uninitialized. The nullable nature of lazy properties offers more flexibility in handling optional or conditionally initialized properties. For instance, if a lazy property is not accessed in certain scenarios, it can remain uninitialized or be assigned a null value to indicate its optional nature.

Thread Safety:

When considering thread safety, lazy properties in Kotlin provide an inherent synchronization mechanism to guarantee that initialization occurs only once, even in multi-threaded scenarios. The lazy delegate is thread-safe by default, ensuring that multiple threads attempting to access the property simultaneously will wait for initialization to complete and share the same initialized value.

In contrast, lateinit properties do not offer built-in thread-safety mechanisms. Developers must take responsibility for ensuring proper initialization of lateinit properties before accessing them in a concurrent environment. Failure to do so can result in race conditions and unpredictable behavior.

Compile-time vs Runtime Errors:

The main distinction between lateinit and lazy in Kotlin is the time of error detection related to property initialization. With the latest properties, if a property is accessed before being initialized, a UninitializedPropertyAccessException is thrown at runtime. This can lead to bugs that are only detected during runtime and may require careful debugging to identify the cause.

In contrast, lazy properties are checked for initialization at compile time. If a lazy property is not properly initialized or if the initialization logic throws an exception, the error is caught during compilation, allowing developers to address the issue before deploying the code. This early error detection improves code quality and reduces the likelihood of runtime crashes.



  • Allows for deferred initialization.

  • The latest properties must be non-nullable.

  • Require manual initialization.


  • Initialization occurs when the property is first accessed.

  • Can be nullable and provide built-in thread-safety mechanisms.

I hope this article will help you to understand the concept and best usages of lateinit and lazy in Kotlin.

That's it for today. Happy Coding...

If get to know something new by reading my articles, don't forget to endorse me on LinkedIn

Read about SOLID Principles

Read about Android Development