Kotlin how to check lateinit property is initialized

Kotlin how to check lateinit property is initialized

How to check if a lateinit variable is initialized in Kotlin?

1. Introduction

In this short article, we are going to present how to find out that lateinit variable in Kotlin has been initialized.

2. Late-initialized variable

The non-null variables usually must be initialized in the constructor and this is the normal behavior in many programming languages, Kotlin is not an exception in this case. However, that approach is not so obvious in cases when variables are initialized through the dependency injection or other configuration methods. In such situations, we cannot add variable initializer in the constructor but still want to avoid constantly checking if variables are null in the class body.

To handle such cases Kotlin introduced the lateinit modifier:

In this example, the lateinitTest is marked with lateinit modifier. This adds some extra features to this variable.

3. Checking if the lateinit variable is initialized

The output will be:

Note that lateinit modifier could be used only on non-primitive types and on property that does not have a custom getter or setter.

When we try to access a lateinit property before it has been initialized the special exception will be thrown with all information about what went wrong.

This will produce the following exception:

4. Conclusion

In this short tutorial, we present a way to check if the lateinit variable has been initialized. Kotlin luckily provides a dedicated property that does this job well.

How to check if a «lateinit» variable has been initialized?

I wonder if there is a way to check if a lateinit variable has been initialized. For example:

Kotlin how to check lateinit property is initialized. Смотреть фото Kotlin how to check lateinit property is initialized. Смотреть картинку Kotlin how to check lateinit property is initialized. Картинка про Kotlin how to check lateinit property is initialized. Фото Kotlin how to check lateinit property is initialized

9 Answers 9

Trending sort

Trending sort is based off of the default sorting method — by highest score — but it boosts votes that have happened recently, helping to surface more up-to-date answers.

It falls back to sorting by highest score if no posts are trending.

Switch to Trending sort

There is a lateinit improvement in Kotlin 1.2 that allows to check the initialization state of lateinit variable directly:

See the annoucement on JetBrains blog or the KEEP proposal.

UPDATE: Kotlin 1.2 has been released. You can find lateinit enhancements here:

Kotlin how to check lateinit property is initialized. Смотреть фото Kotlin how to check lateinit property is initialized. Смотреть картинку Kotlin how to check lateinit property is initialized. Картинка про Kotlin how to check lateinit property is initialized. Фото Kotlin how to check lateinit property is initialized

Kotlin how to check lateinit property is initialized. Смотреть фото Kotlin how to check lateinit property is initialized. Смотреть картинку Kotlin how to check lateinit property is initialized. Картинка про Kotlin how to check lateinit property is initialized. Фото Kotlin how to check lateinit property is initialized

You can easily do this by:

But if you are inside a listener or inner class, do this:

Note: The above statements work fine if you are writing them in the same file(same class or inner class) where the variable is declared but this will not work if you want to check the variable of other class (which could be a superclass or any other class which is instantiated), for ex:

And to check if str is initialized:

Kotlin how to check lateinit property is initialized. Смотреть фото Kotlin how to check lateinit property is initialized. Смотреть картинку Kotlin how to check lateinit property is initialized. Картинка про Kotlin how to check lateinit property is initialized. Фото Kotlin how to check lateinit property is initialized

What we are doing here: checking isInitialized for field str of Test class in Test2 class. And we get an error backing field of var is not accessible at this point. Check a question already raised about this.

“lateinit” Variable in Kotlin

In Kotlin, there are some tokens that cannot be used as identifiers for naming variables, etc. Such tokens are known as keywords. In simple words, keywords are reserved and have special meaning to the compiler, hence they can’t be used as identifiers. For example,

“lateinit” keyword:

The “lateinit” keyword in Kotlin as the name suggests is used to declare those variables that are guaranteed to be initialized in the future.

“lateinit” variable:

A variable that is declared using “lateinit” keyword is known as “lateinit” variable.

Syntax:

lateinit var myVariable: Int

This article focuses on how to check whether “lateinit” variable is initialized.

How to check if a “lateinit” variable has been initialized?

In Kotlin 1.2 version some changes were made using which we can check whether “lateinit” variable is initialized with the help of isInitialized method.

Syntax:

myVariable.isInitialized

Return value:

false: If myVariable is not initialized yet

true: If myVariable is initialized

Example 1:

In the below program we have declared “myVariable” using “lateinit” keyword. Before initialization, we have checked whether this variable is initialized using isInitialized method. Later we have initialized it as “GFG”. Now we are checking again whether this variable is initialized.

Properties

Declaring properties

Properties in Kotlin classes can be declared either as mutable, using the var keyword, or as read-only, using the val keyword.

To use a property, simply refer to it by its name:

Getters and setters

The full syntax for declaring a property is as follows:

The initializer, getter, and setter are optional. The property type is optional if it can be inferred from the initializer or the getter’s return type, as shown below:

The full syntax of a read-only property declaration differs from a mutable one in two ways: it starts with val instead of var and does not allow a setter:

You can define custom accessors for a property. If you define a custom getter, it will be called every time you access the property (this way you can implement a computed property). Here’s an example of a custom getter:

You can omit the property type if it can be inferred from the getter:

If you define a custom setter, it will be called every time you assign a value to the property, except its initialization. A custom setter looks like this:

If you need to annotate an accessor or change its visibility, but you don’t need to change the default implementation, you can define the accessor without defining its body:

Backing fields

In Kotlin, a field is only used as a part of a property to hold its value in memory. Fields cannot be declared directly. However, when a property needs a backing field, Kotlin provides it automatically. This backing field can be referenced in the accessors using the field identifier:

The field identifier can only be used in the accessors of the property.

A backing field will be generated for a property if it uses the default implementation of at least one of the accessors, or if a custom accessor references it through the field identifier.

For example, there would be no backing field in the following case:

Backing properties

If you want to do something that does not fit into this implicit backing field scheme, you can always fall back to having a backing property:

On the JVM: Access to private properties with default getters and setters is optimized to avoid function call overhead.

Compile-time constants

If the value of a read-only property is known at compile time, mark it as a compile time constant using the const modifier. Such a property needs to fulfil the following requirements:

It must be a top-level property, or a member of an object declaration or a companion object.

It must be initialized with a value of type String or a primitive type

It cannot be a custom getter

The compiler will inline usages of the constant, replacing the reference to the constant with its actual value. However, the field will not be removed and therefore can be interacted with using reflection.

Such properties can also be used in annotations:

Late-initialized properties and variables

Normally, properties declared as having a non-null type must be initialized in the constructor. However, it is often the case that doing so is not convenient. For example, properties can be initialized through dependency injection, or in the setup method of a unit test. In these cases, you cannot supply a non-null initializer in the constructor, but you still want to avoid null checks when referencing the property inside the body of a class.

To handle such cases, you can mark the property with the lateinit modifier:

This modifier can be used on var properties declared inside the body of a class (not in the primary constructor, and only when the property does not have a custom getter or setter), as well as for top-level properties and local variables. The type of the property or variable must be non-null, and it must not be a primitive type.

Accessing a lateinit property before it has been initialized throws a special exception that clearly identifies the property being accessed and the fact that it hasn’t been initialized.

Checking whether a lateinit var is initialized

This check is only available for properties that are lexically accessible when declared in the same type, in one of the outer types, or at top level in the same file.

Overriding properties

Delegated properties

The most common kind of property simply reads from (and maybe writes to) a backing field, but custom getters and setters allow you to use properties so one can implement any sort of behavior of a property. Somewhere in between the simplicity of the first kind and variety of the second, there are common patterns for what properties can do. A few examples: lazy values, reading from a map by a given key, accessing a database, notifying a listener on access.

Such common behaviors can be implemented as libraries using delegated properties.

Safely accessing lateinit properties in Kotlin

Kotlin, by design, doesn’t allow a non-null variable to be left uninitialized during its declaration.

If you’ve been digging into Kotlin you’ll know that a lateinit property allows you to overcome this hurdle.

However, if you’re a complete newbie, lateinit allows you to declare a variable first and then initialize is some point in the future during your app’s execution cycle.

All these seem rosy, so where’s the problem?

The problem occurs when you try to access an uninitialized property. Let’s talk more about that.

Accessing an uninitialized property

Don’t mistake this for a puny exception. It’ll crash your app.

And this is a very common situation to run into. Take this as an example:

You might have a list data being fetched from a remote server and need to initialize a RecyclerView adapter based on that data.

What happens when you try to access that adapter before you actually get the data from the remote server?

Boom! Your app crashes.

So, how to solve this problem?

Taking the rookie approach

The most lucrative solution to this problem would be to make the property a regular nullable one instead of a lateinit var and assign a value later on.

You can do something like this:

And then just do a plain null check whenever you’re accessing the value.

So, why go the traditional route?

Here’s a better solution.

Going the Kotlinish way

If you’re using Kotlin 1.2, you can easily check whether a lateinit variable has been initialized or not. If not, well, you can always use the not null approach.

Anyways, here’s how you can check if a lateinit var has been initialized or not:

According to the official blog post announcing this update, this approach uses reflection to check whether the value has been initialized or not.

Also, a deinitialize method is due for rollout in a future release, probably in Kotlin 1.3.

What’s the motivation here?

When I first encountered the exception mentioned in this article, I had two choices:

I took the latter approach.

I didn’t want to litter my code with null checks. Also, this looks more meaningful.

Traditional is, well, traditional. Go along with the new.

Источники информации:

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *