Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

A Practical Explanation for Initialization Modifiers in Kotlin

DZone's Guide to

A Practical Explanation for Initialization Modifiers in Kotlin

Trying to wrap your head around initialization modifiers in Kotlin? Here's a primer for the lazy and lateinit modifiers as well as some practical use cases.

· Java Zone ·
Free Resource

The CMS developers love. Open Source, API-first and Enterprise-grade. Try BloomReach CMS for free.

Recently, I held a Kotlin Workshop for a client. The workshop's central idea was to spend a couple of hours showing the language itself, going individually through some of its capabilities, and, in the second half, developing a full app able to connect to an API, fetch data, storing it, and displaying it in a RecyclerView.

I found this workshop concept to be apt for an audience new or just starting with Kotlin. Most of the initial concepts are explored or at least touched on, and you have an app with an initial architecture and approach that can, later on, be extended and reused in other professional projects.

Yet at this workshop, I encountered a gap between theoretical concept and practical application. More specifically, it was with initialization properties for Kotlin.

As a daily developer and an occasional trainer, I encounter this gap with a certain regularity. It works like this:

  1. There is a theoretical concept that needs to be explained.
  2. I dust off the theory. I explain its peculiarities. I go through the manual description and its corresponding attributes.
  3. I make sure the audience understands the theoretical concept. I ask them questions, I look for answers. Everything looks fine.
  4. Then I get the question: “Yes, everything is fine, but when do we use this?”

To truly understand a concept, you need to be able to walk and moonwalk over the theoretical domain and the practical applications. It is not enough to understand HOW something works — to know its inner rules and learn the manual or tutorial by heart. You need to come to the point where you can think of a practical implication where it could be needed. That is exactly what engineering and practical sciences are: turning theoretical knowledge into practical work.

At the aforementioned workshop, I got the problematic inquiry: “Yes, we understand how initialization properties work. But can you tell us a practical case where to apply them?”

This article aims to serve as a response to my questioner.

Initialization Properties in Kotlin

Let’s start with all the initialization properties available for us in Kotlin. There is no equivalent mechanism in Java, so if you are coming from that realm, you might find it newfangled.

An initialization property determines, unsurprisingly, how a variable will be initialized. In Java, a variable is initialized when the constructor is called. Easy. And limiting. Kotlin offers us a few more options.

lazy

A lazy property is initialized when it is accessed for the first time. Let's look at the following example:

val aVar by lazy {
    "Hola"
}


Unless you access the aVar, its value will never be set. This is the two-line explanation, although a lazy property has more sugar. The value is computed in only one thread, and all threads will see the same value. Also, the first time you access the Lazy property, the initialization takes place. The second time, this value is remembered and returned. For example, take a look at:

val aVar by lazy {
    println("I am computing this value")
    "Hola"
}

fun main(args: Array<String>) {
    println(aVar)
    println(aVar)
}


This code will actually print the following:

I am computing this value
Hola
Hola


As mentioned in the introduction, the theoretical aspect is easy to grasp. We will return later to the lazy modifier.

lateinit

The modifier lateinit allows us to delay the initialization of a variable. Let’s consider the following piece of code:

lateinit var myVar: MyObject


If you try the above code in your compiler, there will be no error thrown. Try to do it without lateinit, and you will end up with a compilation message.

By writing lateinit, we must later on (and before it is accessed) take care of initializing the variable. If we do not, an exception will be thrown:

Caused by: kotlin.UninitializedPropertyAccessException: lateinit property myVar has not been initialized

Ah! And some more details at the top: lateinit does not work with primitive types. You need to use delegates.

The Practical Territory for Initialization Modifiers

We have grasped the theoretical meaning and taken the first sip of its implications. In order to keep mastering our command of these modifiers, we need to find use cases where we can apply them. Let’s check some of them out.

Dependency Injection

If you use Dagger or similar Dependency Injection frameworks, you might be used to code snippets similar to the following one:

@Inject
lateinit var myVar: MyObject


The variable is actually not initialized, but injected afterward. By using lateinit, we allow the initialization to happen in a later instant.

High-Density Computation or Big Objects

Think of an object that requires an intense computation to be created, or that takes a lot of space in memory. A bitmap is always a good example. You instantiate the object, the object is already in memory, and then you need to wait until you use it. This is an effortless example of a variable that should be declared as a lazy object. Keeping this simple action in mind will optimize your code from the initial instant. The same applies for costly operations, such as opening files from the disk system, etc.

(Juhani Lehtimäki actually pointed out in one conversation that this was a great use case)

Resources

Say you need to access a resource (in Android, this might be drawables, string, dimens…). Unless you are in that state (for instance, an error happening in a particular condition) you do not need to load them. Bingo, this is, again, a suitable scenario for late initialization.

A further consideration: by lazy is restricted only to val. lateinit is only allowed on mutable properties (var).

As a summary, try to think of a variable with its instantiation depending on a particular state. If you can think of an example, you already have a candidate for lazy or late initialization.

I write my thoughts about software engineering and life in general in my Twitter account. If you have liked this article or it helped you, feel free to share it, like it, and/or leave a comment. This is the currency that fuels amateur writers.

Thanks to my colleague and friend Marius Budin for his feedback on this article.

BloomReach CMS: the API-first CMS of the future. Open-source & enterprise-grade. - As a Java developer, you will feel at home using Maven builds and your favorite IDE (e.g. Eclipse or IntelliJ) and continuous integration server (e.g. Jenkins). Manage your Java objects using Spring Framework, write your templates in JSP or Freemarker. Try for free.

Topics:
java ,kotlin ,initialization modifiers ,lazy initialization ,lateinit ,dependency injection ,tutorial

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}