将'lateinit'修饰符与Kotlin中的条件绑定

时间:2019-03-05 04:26:38

标签: kotlin

在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()

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

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

  1. 是否有比这些解决方案更好的解决方案?
  2. 如果不存在其他解决方案,那么哪个是更好的解决方案?我可以使用第二种或第三种解决方案,但我不确定哪种解决方案更好或更干净。

2 个答案:

答案 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的回答,它仍然有点气味。重做以使该属性可为空将使它的访问更加尴尬,但更安全。