Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kotlin: Check if lazy val has been initialised

Tags:

kotlin

Is there a way to tell if a lazy val has been initialised in Kotlin without initialising it in the process?

eg if I have a lazy val, querying if it is null would instantiate it

val messageBroker: MessageBroker by lazy { MessageBroker() } if (messageBroker == null) {     // oops } 

I could potentially use a second variable, but that seems messy.

private var isMessageBrokerInstantiated: Boolean = false val messageBroker: MessageBroker by lazy {     isMessageBrokerInstantiated = true     MessageBroker() }  ...  if (!isMessageBrokerInstantiated) {     // use case } 

Is there some sexy way of determining this, like if (Lazy(messageBroker).isInstantiated())?

Related (but not the same): How to check if a "lateinit" variable has been initialized?

like image 367
Tom Avatar asked Mar 01 '17 03:03

Tom


People also ask

How do you check if a lazy variable is initialized Kotlin?

There is a way, but you have to access the delegate object which is returned by lazy {} : val messageBrokerDelegate = lazy { MessageBroker() } val messageBroker by messageBrokerDelegate if(messageBrokerDelegate. isInitialized()) ... isInitialized is a public method on interface Lazy<T> , here are the docs.

How do you initialize a lazy in Kotlin?

* To create an instance of [Lazy] use the [lazy] function. * Gets the lazily initialized value of the current Lazy instance. * Once the value was initialized it must not change during the rest of lifetime of this Lazy instance.

What is the difference between Lateinit and lazy in Kotlin?

In the above code, you can see that the object of the HeavyClass is created only when it is accessed and also the same object is there all over the main() function. Lazy is mainly used when you want to access some read-only property because the same object is accessed throughout.

What if Lateinit is not initialized?

If you try accessing Lateinit variables without initializing, it will throw an exception stating that it is not initialized or properly being accessed.


2 Answers

There is a way, but you have to access the delegate object which is returned by lazy {}:

val messageBrokerDelegate = lazy { MessageBroker() } val messageBroker by messageBrokerDelegate  if(messageBrokerDelegate.isInitialized())     ... 

isInitialized is a public method on interface Lazy<T>, here are the docs.

like image 121
voddan Avatar answered Oct 08 '22 17:10

voddan


Since Kotlin 1.1, you can access a property delegate directly using .getDelegate().

You can write an extension property for a property reference that checks that it has a Lazy delegate that has already been initialized:

/**  * Returns true if a lazy property reference has been initialized, or if the property is not lazy.  */ val KProperty0<*>.isLazyInitialized: Boolean     get() {         if (this !is Lazy<*>) return true          // Prevent IllegalAccessException from JVM access check on private properties.         val originalAccessLevel = isAccessible         isAccessible = true         val isLazyInitialized = (getDelegate() as Lazy<*>).isInitialized()         // Reset access level.         isAccessible = originalAccessLevel         return isLazyInitialized     } 

Then at the use site:

val messageBroker: MessageBroker by lazy { MessageBroker() }  if (this::messageBroker.isLazyInitialized) {     // ... do stuff here } 

This solution requires kotlin-reflect to be on the classpath. With Gradle, use
compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"

The isAccessible = true part is required for the .getDelegate(), because otherwise it cannot access the private field storing the delegate reference.

like image 27
hotkey Avatar answered Oct 08 '22 19:10

hotkey