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

Tom*_*Tom 32 kotlin

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

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

val messageBroker: MessageBroker by lazy { MessageBroker() }
if (messageBroker == null) {
    // oops
}
Run Code Online (Sandbox Code Playgroud)

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

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

...

if (!isMessageBrokerInstantiated) {
    // use case
}
Run Code Online (Sandbox Code Playgroud)

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

相关(但不相同):如何检查"lateinit"变量是否已初始化?

vod*_*dan 38

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

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

if(messageBrokerDelegate.isInitialized())
    ...
Run Code Online (Sandbox Code Playgroud)

isInitialized是接口上的公共方法Lazy<T>,这里是文档.

  • 请注意,您也可以直接使用`Lazy`而不是委托,并使用[`Lazy.value`]访问延迟评估的值(https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-懒惰/ value.html).另请参见http://stackoverflow.com/q/38794502/3255152. (3认同)

hot*_*key 24

从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
    }
Run Code Online (Sandbox Code Playgroud)

然后在使用网站:

val messageBroker: MessageBroker by lazy { MessageBroker() }

if (this::messageBroker.isLazyInitialized) {
    // ... do stuff here
}
Run Code Online (Sandbox Code Playgroud)

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

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

  • 我必须删除“if (this !is Lazy&lt;*&gt;) return true”,否则它可以工作。1.3 的变化? (2认同)
  • 如果您正在使用 R8(可能也是 ProGuard,未测试),则需要从缩小中排除两件事:包含该字段的类必须是可访问的,以及其父类和已实现的接口。并且该字段本身必须标记为`@delegate:Keep`。 (2认同)

Ste*_*ley 8

热键的解决方案的基础上,您可以创建一个isLazyInitialized属性(而不是函数),以与lateinit变量的isInitialized属性保持一致.

此外,没有必要处理null情况.

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()
    }
Run Code Online (Sandbox Code Playgroud)