【问题标题】:Kotlin: Null check in if blockKotlin:如果阻止则为空签入
【发布时间】:2019-04-15 21:53:03
【问题描述】:

我最近开始学习 Kotlin。我无法理解的一件事是空检查块。下面的语句被认为是不安全的,编译器不允许你编译它。

    var testVar: String? = null;

    // if (testVar != null )
    {
        // Doing some work....
        println(testVar.length)
    }

但是,当您取消注释 if 行时,一切正常。这似乎很棒。

但是如果 // Doing some work.... 的计算量很大并且另一个线程将 testVar 的值更改为 null 而该线程位于 // Doing some work 行中怎么办?在这种情况下:

  • 程序是否抛出 NullPointerException?
  •      或者:
  • 字节码是否缓存了 testVar 的值并在 if 块中使用缓存的值?

【问题讨论】:

    标签: kotlin


    【解决方案1】:

    在您的初始示例中,您的 var 是函数的本地函数吗?例如:

    fun doStuff() {
        var testVar: String? = null
    
        if (testVar != null) {
            println(testVar.length)
        }
    }
    

    在这种情况下,没有其他作用域引用testVar,所以没有其他东西可以改变它。但是,如果 var 是类属性,即

    class MyClass {
        var testVar: String? = null
    
        fun doStuff() {
            if (testVar != null) {
                println(testVar.length)
            }
        }
    }
    

    这将无法编译,因为testVar 可能在检查和使用之间被另一个线程设置为 null。

    更进一步,如果你想变得狡猾:

    fun doStuff() {
        var testVar: String? = null
    
        fun trickyFunction() {
            testVar = null
        }
    
        if (testVar != null) {
            trickyFunction()
            println(testVar.length)
        }
    }
    

    编译器将失败,因为您的变量被不断变化的闭包捕获。因此,一般而言,如果您能够通过智能强制转换为非 null 来使用该变量,则不必担心 NPE 的任何可能性。

    对于第二种情况(var 属性),最好依靠.let 来捕获对当前值的不可变引用,即

    testVar?.let { capturedTestVar ->
        println(capturedTestVar.length)
    }
    

    【讨论】:

    • 实际上有很多内置的作用域函数可以根据上下文派上用场:letrunalsoapply
    猜你喜欢
    • 2017-11-18
    • 2021-10-28
    • 1970-01-01
    • 2020-06-01
    • 1970-01-01
    • 2019-09-22
    • 1970-01-01
    • 1970-01-01
    • 2011-04-09
    相关资源
    最近更新 更多