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?
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.
* 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.
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.
If you try accessing Lateinit variables without initializing, it will throw an exception stating that it is not initialized or properly being accessed.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With