Kotlin:检查lazy val是否已初始化

时间:2017-03-01 03:38:52

标签: kotlin

有没有办法判断是否在Kotlin中初始化了懒惰的val而没有在此过程中初始化它?

例如,如果我有一个懒惰的val,查询它是否为null将实例化它

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

我可能会使用第二个变量,但这看起来很混乱。

private var isMessageBrokerInstantiated: Boolean = false
val messageBroker: MessageBroker by lazy {
    isMessageBrokerInstantiated = true
    MessageBroker()
}

...

if (!isMessageBrokerInstantiated) {
    // use case
}

是否有一些性感的方法来确定这一点,例如if (Lazy(messageBroker).isInstantiated())

相关(但不相同):How to check if a "lateinit" variable has been initialized?

3 个答案:

答案 0 :(得分:35)

有一种方法,但您必须访问lazy {}返回的委托对象:

val messageBrokerDelegate = lazy { MessageBroker() }
val messageBroker by messageBrokerDelegate

if(messageBrokerDelegate.isInitialized())
    ...

isInitialized是接口Lazy<T>上的公开方法,此处为docs

答案 1 :(得分:21)

从Kotlin 1.1开始,您可以使用.getDelegate()直接访问属性委托。

您可以为属性引用编写扩展属性,以检查它是否已经初始化了Lazy委托:

/**
 * 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
    }

然后在使用地点:

val messageBroker: MessageBroker by lazy { MessageBroker() }

if (this::messageBroker.isLazyInitialized) {
    // ... do stuff here
}

此解决方案需要kotlin-reflect位于类路径上。使用Gradle,使用
compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" 功能

isAccessible = true需要.getDelegate()部分,因为否则它无法访问存储委托引用的私有字段。

答案 2 :(得分:7)

hotkey's solution上构建,您可以创建一个isLazyInitialized属性(而不是函数),以与lateinit vars的isInitialized属性保持一致。

此外,没有必要处理null case。

import kotlin.reflect.KProperty0,
import kotlin.reflect.jvm.isAccessible

val KProperty0<*>.isLazyInitialized: Boolean
    get() {
        // Prevent IllegalAccessException from JVM access check
        isAccessible = true
        return (getDelegate() as Lazy<*>).isInitialized()
    }