The new Certification Class of REST With Spring is out:

>> CHECK OUT THE COURSE

1. Overview

In this article, we’ll be looking at one of the most interesting features in Kotlin syntax – lazy initialization.

We’ll also be looking at the lateinit keyword that allows us to trick compiler and initialize non-null fields in the body of class – instead of in the constructor.

2. Lazy Initialization Pattern in Java

Sometimes we need to construct objects that have a cumbersome initialization process. Also, often we cannot be sure that object, for which we paid the cost of initialization at the start of our program, will be used in our program at all.

The concept of ‘lazy initialization’ was designed to prevent unnecessary initialization of objects. In Java, creating an object in a lazy and thread-safe way is not an easy thing to do. Patterns like Singleton have significant flaws in multithreading, testing, etc. – and they’re now widely known as anti-patterns to be avoided.

Alternatively, we can leverage the static initialization of inner object in Java to achieve laziness:

public class ClassWithHeavyInitialization {
 
    private ClassWithHeavyInitialization() {
    }

    private static class LazyHolder {
        public static final ClassWithHeavyInitialization INSTANCE = new ClassWithHeavyInitialization();
    }

    public static ClassWithHeavyInitialization getInstance() {
        return LazyHolder.INSTANCE;
    }
}

Notice how, only when we will call the getInstance() method on ClassWithHeavyInitialization, the static LazyHolder class will be loaded, and the new instance of the ClassWithHeavyInitialization will be created. Next, the instance will be assigned to the static final INSTANCE reference.

We can test that the getInstance() is returning the same instance every time it is called:

@Test
public void giveHeavyClass_whenInitLazy_thenShouldReturnInstanceOnFirstCall() {
    // when
    ClassWithHeavyInitialization classWithHeavyInitialization 
      = ClassWithHeavyInitialization.getInstance();
    ClassWithHeavyInitialization classWithHeavyInitialization2 
      = ClassWithHeavyInitialization.getInstance();

    // then
    assertTrue(classWithHeavyInitialization == classWithHeavyInitialization2);
}

That’s technically OK but of course a little bit too complicated for such a simple concept.

3. Lazy Initialization in Kotlin

We can see that using lazy initialization pattern in Java is quite cumbersome. We need to write a lot of boilerplate code to achieve our goal. Luckily, the Kotlin language has built-in support for lazy initialization.

To create an object that will be initialized at the first access to it, we can use the lazy method:

@Test
fun givenLazyValue_whenGetIt_thenShouldInitializeItOnlyOnce() {
    // given
    val numberOfInitializations: AtomicInteger = AtomicInteger()
    val lazyValue: ClassWithHeavyInitialization by lazy {
        numberOfInitializations.incrementAndGet()
        ClassWithHeavyInitialization()
    }
    // when
    println(lazyValue)
    println(lazyValue)

    // then
    assertEquals(numberOfInitializations.get(), 1)
}

As we can see, the lambda passed to the lazy function was executed only once.

When we’re accessing the lazyValue for the first time – an actual initialization happened, and the returned instance of the ClassWithHeavyInitialization class was assigned to the lazyValue reference. Subsequent access to the lazyValue returned the previously initialized object.

We can pass the LazyThreadSafetyMode as an argument to the lazy function. Default publication mode is SYNCHRONIZED meaning that only single thread can initialize the given object.

We can pass a PUBLICATION as a mode – which will cause that every thread can initialize given property. The object assigned to the reference will be the first returned value – so the first thread wins.

Let’s have a look at that scenario:

@Test
fun whenGetItUsingPublication_thenCouldInitializeItMoreThanOnce() {
 
    // given
    val numberOfInitializations: AtomicInteger = AtomicInteger()
    val lazyValue: ClassWithHeavyInitialization
      by lazy(LazyThreadSafetyMode.PUBLICATION) {
        numberOfInitializations.incrementAndGet()
        ClassWithHeavyInitialization()
    }
    val executorService = Executors.newFixedThreadPool(2)
    val countDownLatch = CountDownLatch(1)
 
    // when
    executorService.submit { countDownLatch.await(); println(lazyValue) }
    executorService.submit { countDownLatch.await(); println(lazyValue) }
    countDownLatch.countDown()

    // then
    executorService.awaitTermination(1, TimeUnit.SECONDS)
    executorService.shutdown()
    assertEquals(numberOfInitializations.get(), 2)
}

We can see that starting two threads at the same time cause initialization of the ClassWithHeavyInitialization happen twice.

There’s also a third mode – NONE – but it shouldn’t be used in the multithreaded environment as its behavior is undefined.

4. Kotlin’s lateinit

In Kotlin, every non-nullable class property that is declared in the class needs to be assigned in the constructor; otherwise, we’ll get a compiler error. On the other hand, there are some cases in which the variable can be assigned dynamically by for example dependency injection.

To defer initialization of the variable, we can specify that a field is lateinit. We are informing the compiler that this will variable will be assigned later and we are freeing the compiler from the responsibility of making sure that this variable gets initialized:

lateinit var a: String
 
@Test
fun givenLateInitProperty_whenAccessItAfterInit_thenPass() {
    // when
    a = "it"
    println(a)

    // then not throw
}

If we forget to initialize the lateinit property, we’ll get an UninitializedPropertyAccessException:

@Test(expected = UninitializedPropertyAccessException::class)
fun givenLateInitProperty_whenAccessItWithoutInit_thenThrow() {
    // when
    println(a)
}

5. Conclusion

In this quick tutorial, we looked at the lazy initialization of objects.

Firstly, we saw how to create a thread-safe lazy initialization in Java. We saw that it is a very cumbersome and needs a lot of boilerplate code.

Next, we delved into Kotlin lazy keyword that is used for lazy initialization of properties. In the end, we saw how to defer assigning variables using the lateinit keyword.

The implementation of all these examples and code snippets can be found in the GitHub project – this is a Maven project, so it should be easy to import and run as it is.

Go deeper into building a REST API with Spring:

>> CHECK OUT THE COURSE

Leave a Reply

3 Comments on "Lazy Initialization in Kotlin"

Notify of
avatar
Sort by:   newest | oldest | most voted
Dusan Odalovic
Guest

Hi, thanks for this article. One remark there:

… “In Kotlin, every variable that is declared in the class needs to be assigned in the constructor; otherwise …”

Every non nullable class property that is ….

Grzegorz Piwowarek
Guest

Thanks! 🙂

die toten Rosen
Guest

Hi, I just wanted to clarify that lazy is not a keyword in kotlin, it is a function which receives a lambda (the initialization block). But in this case by is a keyword

wpDiscuz