有没有办法判断是否在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?
答案 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()
}