在Kotlin中,我们有lateinit
修饰符来进行惰性变量初始化,而不是var something: Something? = null
。
在我的情况下,我有一个Element
的列表,我想在拥有第一个对象时将其分配给lateinit
变量。
因此,我尝试了几种方法来实现这一目标。
第一,使用“ firstOrNull()”方法
lateinit var applicationHolder: ApplicationHolder
applicationHolder = env.getElementsAnnotatedWith(InjectApplication::class.java)
.map {
ApplicationHolder(it, (it as TypeElement).asClassName(), it.simpleName.toString()).apply {
val component = it.getAnnotation(InjectApplication::class.java).getComponent()
componentClass = component
}
}.firstOrNull()
第一个解决方案失败,因为applicationHolder
不接受ApplicationHolder的Nullable类型。 (类型推断失败。预期的类型不匹配:推断的类型为ApplicationHolder?但预期为ApplicationHolder。)
尽管我可以使用first
而不是firstOrNull
来实现这一点,但这太危险了,因为列表可以为空。
第二,使用if-condition
val item = env.getElementsAnnotatedWith(InjectApplication::class.java)
.map {
ApplicationHolder(it, (it as TypeElement).asClassName(), it.simpleName.toString()).apply {
val component = it.getAnnotation(InjectApplication::class.java).getComponent()
componentClass = component
}
}.firstOrNull()
if (item != null) {
applicationHolder = item
}
第二个解决方案成功编译并运行良好。
第三,使用支持属性(实际上,此解决方案不使用lateinit修饰符)
val applicationHolder: ApplicationHolder
get() {
return _applicationHolder ?: throw NullPointerException("Not initialized")
}
private var _applicationHolder: ApplicationHolder? = null
_applicationHolder = env.getElementsAnnotatedWith(InjectApplication::class.java)
.map {
ApplicationHolder(it, (it as TypeElement).asClassName(), it.simpleName.toString()).apply {
val component = it.getAnnotation(InjectApplication::class.java).getComponent()
componentClass = component
}
}.firstOrNull()
第三个解决方案成功编译并运行良好。
简而言之,我的问题如下。
答案 0 :(得分:1)
您为什么在这里对可为null的类型使用lateinit?
这对我敲响了警钟:
这太危险了,因为列表可以为空。
如果您尝试访问Lateinit对象而不对其进行初始化,则您的应用程序将崩溃。如果一定要初始化,则应使用Lateinit。
我会将代码更改为您避免使用的代码:var something: Something? = null
然后使用firstOrNull()方法。 kotlin null安全类型系统将强制您处理null,从而获得安全代码!
答案 1 :(得分:0)
可以通过调用lateinit
来检查this::applicationHolder.isInitialized
是否已初始化。 (这是在Kotlin 1.2中引入的;信息here。)
但是,按照@ user8159708的回答,它仍然有点气味。重做以使该属性可为空将使它的访问更加尴尬,但更安全。