Kotlin: нулевая проверка, если блок

#kotlin

#kotlin

Вопрос:

Недавно я начал изучать Kotlin. Одна вещь, которую я не могу понять, — это блоки проверки null. Следующий оператор считается небезопасным, и компилятор не позволит вам его скомпилировать.

     var testVar: String? = null;

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

Но когда вы раскомментируете if строку, все работает. Это кажется отличным.

Но что, если // Doing some work.... это дорого с точки зрения вычислений, и другой поток изменяет значение testVar to null , пока этот поток находится в // Doing some work очереди? В этом сценарии:

  • Выдает ли программа исключение NullPointerException?
  • или:
  • Кэширует ли байт-код значение testVar и использует ли кэшированное значение внутри блока if?

Ответ №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)
    }
}
 

Компилятор завершится с ошибкой, поскольку ваша переменная будет захвачена изменяющимся замыканием. Итак, в общем, если вы можете использовать переменную с помощью интеллектуального приведения к ненулевому значению, вам не нужно беспокоиться о каких-либо потенциальных NPE.

Для второго сценария (свойства переменной) предпочтительнее полагаться на .let получение неизменяемой ссылки на текущее значение, т.е.

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

Комментарии:

1.На самом деле существует множество встроенных функций определения области видимости, которые пригодятся в зависимости от контекста : let run also apply .