变量的返回值显然可以为null但实际上不能

时间:2017-04-15 06:20:54

标签: android kotlin

在Kotlin中进行编码的惯用方法是什么?

   private var someVar: SomeClass? = null

   private fun getSomeVar(): SomeClass {
        if (someVar == null) {
            someVar = getDefaultSomeVar()
        }

        return someVar
    }

Android Studio警告我返回类型。但是,在Java中,这段代码是正确的,也是惯用的。我的意思是,不是将返回类型更改为SomeClass?,而是还有更好的方法吗?

实际上,getSomeVar()永远不会返回null

3 个答案:

答案 0 :(得分:5)

编译器抱怨,因为理论上,不同的线程可以在赋值和return语句之间更改someVar

这里的惯用解决方案是使用property delegation

private val someVar: SomeClass by lazy { getDefaultSomeVar() }

首次以线程安全方式访问属性时初始化该属性。另请注意,它现在是一个不可为空的val,而不是可空的var,这使得它通常更容易使用。

您确实无法在以后修改它。如果它需要是可变的,你现在必须自己做。有关示例实现,请参阅此SO问题:Kotlin lazy default property

以下两个解决方案将问题中的方法(“java方式”)视为理所当然,并且只显示防止编译器警告的方法。但是,在您的情况下,这些建议,因为它们都比延迟初始化属性有缺点:

1)引入局部变量。这个变量不会被其他线程变异,并允许编译器进行Smart Cast:

private fun getSomeVar(): SomeClass {
    var value = someVar
    if(value == null) {
        value = getDefaultSomeVar()
        someVar = value
    }

    return value
}

然而,该方法本身仍然不是线程安全的。在多线程环境中,可以多次调用getDefaultSomeVar(),并且无法保证此方法的返回值等于someVar

2)使用!!:双重操作员。这会将可空类型转换为非可空类型。但现在你失去了kotlin编译器强制执行的保护和null safety

return someVar!!

正如文档所说:'如果你想要一个NPE,你可以拥有它'

答案 1 :(得分:0)

你可以写:

return someVar!!

这将返回一个非空值,但如果它为null,则会抛出一个NPE。

答案 2 :(得分:0)

它可能更短,没有任何警告

 private fun getSomeVar(): SomeClass {
        return someVar?:getDefaultSomeVar()
    }