有一些方法可以在 Kotlin 中完成空值检查:
1.
if(myVar != null) {
foo(myVar)
}
2.
myVar?.let {
foo(it)
}
3.
myVar?.run {
foo(this)
}
这些方式有什么区别?
有什么理由(性能、最佳实践、代码风格等)为什么我应该更喜欢其他方式?
有一些方法可以在 Kotlin 中完成空值检查:
1.
if(myVar != null) {
foo(myVar)
}
2.
myVar?.let {
foo(it)
}
3.
myVar?.run {
foo(this)
}
这些方式有什么区别?
有什么理由(性能、最佳实践、代码风格等)为什么我应该更喜欢其他方式?
!!是告诉编译器我确定变量的值不为空,如果为空,则抛出空指针异常(NPE),其中为?。是告诉编译器我不确定变量的值是否为空,如果为空,则不要抛出任何空指针。
使用可为空属性的另一种方法是安全调用运算符?。如果属性不为 null,则调用该方法;如果该属性为 null,则返回 null,而不会引发 NPE(空指针异常)。
nullableVariable?.someMethodCall()
方式 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 标准函数的好文章。
您问题中的示例并未显示做出决定的真正原因。
首先,由于您没有使用 的返回值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
.
与 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 异常或保护您的应用程序崩溃
你想达到什么
您想要实现的是 Kotlin 编译器对您正在使用的变量进行智能转换。
在您的所有三个示例中,编译器都可以做到这一点。
例子:
if(myVar != null) {
foo(myVar) // smart cast: the compiler knows, that myVar can never be null here
}
选择
使用哪一个选项,真的是风格问题。你不应该做的是经常混合它。使用一个并坚持下去。
您无需担心性能,因为let和run是内联的(请参阅内联函数)。这意味着它们的代码(主体)在编译时被复制到调用站点,因此没有运行时开销。
所有三个代码在操作方面都表现相同的空值检查。
?. 用于链式操作。
bob?.department?.head?.name // if any of the properties in it is null it returns null
要仅对非空值执行链式操作,可以将安全调用运算符与 let 一起使用
myVar?.let {
foo(it)
}
上面的代码有利于代码风格和性能
更多详细信息请参阅 空安全
三者大致相当。
该if
案例更像大多数其他语言,因此许多开发人员可能会发现它更易于阅读。
但是,一个区别是if
case 将读取myVar
两次的值:一次用于检查,另一次将其传递给foo()
. 这会有所不同,因为 ifmyVar
是一个属性(即可能被另一个线程更改的东西),那么编译器会警告它可能在检查后被设置为 null 。如果这是一个问题(例如,因为foo()
需要一个非空参数),那么您将需要使用其他情况之一。
出于这个原因,这种let
情况在 Kotlin 中已成为相当普遍的做法。(这个run
案子做的事情差不多,但由于某种原因,这种事情并不那么受欢迎。我不知道为什么。)
另一种解决方法是分配myVar
一个临时值,对其进行测试,然后使用它。这也更像其他语言,但更冗长;许多人更喜欢这种情况的简洁性let
——尤其是当myVar
它实际上是一个复杂的表达方式时。