1

有一些方法可以在 Kotlin 中完成空值检查:

1.

if(myVar != null) {
    foo(myVar)
}

2.

myVar?.let { 
    foo(it)
}

3.

myVar?.run { 
    foo(this)
}

这些方式有什么区别?

有什么理由(性能、最佳实践、代码风格等)为什么我应该更喜欢其他方式?

4

7 回答 7

1

!!是告诉编译器我确定变量的值不为空,如果为空,则抛出空指针异常(NPE),其中为?。是告诉编译器我不确定变量的值是否为空,如果为空,则不要抛出任何空指针。

使用可为空属性的另一种方法是安全调用运算符?。如果属性不为 null,则调用该方法;如果该属性为 null,则返回 null,而不会引发 NPE(空指针异常)。

nullableVariable?.someMethodCall()
于 2018-12-26T12:20:31.920 回答
0

方式 2 和 3 对于 Kotlin 来说更惯用。这两个功能非常相似。参数传递几乎没有区别。

例如,我们有一个可为空的变量:

var canBeNull: String? = null

当您与T.run您一起使用扩展函数调用并传入this闭包时。

    canBeNull?.run {
        println(length) // `this` could be omitted
    }

当你打电话时,T.let你可以像 lambda argument 一样使用它it

    canBeNull?.let {
        myString -> println(myString.length) // You could convert `it` to some other name
    }

一篇关于 Kotlin 标准函数的好文章。

于 2018-12-26T09:34:56.600 回答
0

您问题中的示例并未显示做出决定的真正原因。

首先,由于您没有使用 的返回值foo,因此您应该既不使用let也不使用run。您的选择介于also和之间apply

其次,由于您已经有了要在变量中进行空检查的结果,因此差异会逐渐消失。这是一个更好的激励例子:

complexCall(calculateArg1(), calculateArg2())?.also {
    results.add(it)
}

val result = complexCall(calculateArg1(), calculateArg2())
if (result != null) {
    results.add(result)
}

第二个示例声明了一个标识符 ,result它现在可用于词法范围的其余部分,即使您只用一行就完成了它。

另一方面,第一个示例保持所有内容自包含,当您继续阅读其余代码时,您 100% 确信您不必记住result.

于 2018-12-26T10:00:53.687 回答
0

与 Java 相比,Kotlin 具有 NullPoint-Exception 的新功能。

基本上当我们用 Java 进行编码时,我们必须检查!! 在每一个飞行中。

但是在 Kotlin 中,首先实现是简单的方法

就像,

假设,在 Kotlin

var 响应:Json?=Null

响应:Json?.let {

如果响应不是 Null,这部分将自动处理....然后这个 Block start Executing }?.run { This is Nullable But, where we can put Warring } 所以,我建议你们开始在 Kotlin 中使用这个功能由 Kotlin 提供。

(Flied)?.let { Not Null Value Comes Under }?.run{ Null Value Code }

这将处理 NullPoint 异常或保护您的应用程序崩溃

于 2018-12-26T13:50:15.367 回答
0

你想达到什么

您想要实现的是 Kotlin 编译器对您正在使用的变量进行智能转换。

在您的所有三个示例中,编译器都可以做到这一点。

例子:

if(myVar != null) {
    foo(myVar) // smart cast: the compiler knows, that myVar can never be null here
}

选择

使用哪一个选项,真的是风格问题。你不应该做的是经常混合它。使用一个并坚持下去。

您无需担心性能,因为letrun是内联的(请参阅内联函数)。这意味着它们的代码(主体)在编译时被复制到调用站点,因此没有运行时开销。

于 2018-12-26T14:24:18.577 回答
0

所有三个代码在操作方面都表现相同的空值检查。

?. 用于链式操作。

 bob?.department?.head?.name // if any of the properties in it is null it returns null

要仅对非空值执行链式操作,可以将安全调用运算符与 let 一起使用

myVar?.let { 
foo(it)
}

上面的代码有利于代码风格和性能

更多详细信息请参阅 空安全

于 2018-12-26T08:37:14.860 回答
0

三者大致相当。

if案例更像大多数其他语言,因此许多开发人员可能会发现它更易于阅读。

但是,一个区别是ifcase 将读取myVar两次的值:一次用于检查,另一次将其传递给foo(). 这会有所不同,因为 ifmyVar是一个属性(即可能被另一个线程更改的东西),那么编译器会警告它可能在检查后被设置为 null 。如果这是一个问题(例如,因为foo()需要一个非空参数),那么您将需要使用其他情况之一。

出于这个原因,这种let情况在 Kotlin 中已成为相当普遍的做法。(这个run案子做的事情差不多,但由于某种原因,这种事情并不那么受欢迎。我不知道为什么。)

另一种解决方法是分配myVar一个临时值,对其进行测试,然后使用它。这也更像其他语言,但更冗长;许多人更喜欢这种情况的简洁性let——尤其是当myVar它实际上是一个复杂的表达方式时。

于 2018-12-26T09:48:48.337 回答