首页 > 解决方案 > 在 Kotlin 中将“lateinit”修饰符与条件绑定

问题描述

在 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不接受 Nullable 类型的 ApplicationHolder。(类型推断失败。预期类型不匹配:推断类型为 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()

第三个解决方案成功编译并运行良好。

简而言之,我的问题如下。

  1. 有没有比这些解决方案更好的解决方案来实现我的目标?
  2. 如果不存在另一个解决方案,哪个是干净或更好的解决方案?我可以使用第二种或第三种解决方案,但我没有信心哪个是干净的或更好的。

标签: kotlin

解决方案


你为什么在这里使用 lateinit 而不是可以为空的类型?

这给我敲响了警钟:

这太危险了,因为列表可能为空。

如果你试图访问一个 lateinit 对象而不初始化它,你的应用程序将会崩溃。如果肯定会初始化 Lateinit,则应该使用它。

我会将代码更改为您避免的代码:var something: Something? = null

然后使用 firstOrNull() 方法。kotlin 空安全类型系统将强制您处理空值,从而生成安全代码!


推荐阅读