Kotlin空值检查与!!不短路评估?

Kotlin空值检查与!!不短路评估?,kotlin,Kotlin,在if语句评估中,Kotlin空安全检查是否未短路? 请参见下面的示例 fun main(){ var myEmps : List<Emp>? = null println(myEmps) //null var address = if(myEmps?.get(0)!!.address?.line1!=null) myEmps?.get(0)!!.address!!.line1 else "no address" //Exception i

在if语句评估中,Kotlin空安全检查是否未短路? 请参见下面的示例

fun main(){
    var myEmps : List<Emp>? = null
    println(myEmps) //null
    var address = if(myEmps?.get(0)!!.address?.line1!=null) myEmps?.get(0)!!.address!!.line1 else "no address" //Exception in thread "main" java.lang.NullPointerException
    println(address)
}

data class Emp (var name: String?, var address: Address?) {}
data class Address(var line1: String?, var line2: String) {}

所以,请检查!!带有此短路警告不适用,始终确保正确检查整个链条?如果是这样的话,这在对象链验证的场景中有多有用?

您应该将调用链看作是一系列计算结果的步骤。链上的每个调用都是在前面的评估值上调用的。任何
?。
调用都将计算为可为空的类型

首先是
myEmps
,它是一个
列表?

然后调用
?。获取(0)
。由于null safe
?。
调用,这将计算为一个
Emp?

然后你调用
Emp?
上<代码>
表示将其计算为不可为null的
Emp
或抛出KotlinNullPointerException。它本质上与空安全调用相反

如果您想要空安全,您实际上需要的是继续使用空安全
?。
一旦您有了可空的内容,就会调用整个链,因此您应该替换
。像这样:

var address = if(myEmps?.get(0)?.address?.line1 != null) myEmps?.get(0)?.address!!.line1 else "no address"
第二次使用
可以保留,因为它发生在您的
!=空值
检查,以便您知道
Emp?
不会计算为
空值
。但重复那长长的通话链是很笨拙的。通过使用Elvis运算符
?:
可以消除此if语句,如下所示:

var address = myEmps?.get(0)?.address?.line1 ?: "no address"

你应该把一系列的调用看作是一系列的步骤,这些步骤对某些东西进行评估。链上的每个调用都是在前面的评估值上调用的。任何
?。
调用都将计算为可为空的类型

首先是
myEmps
,它是一个
列表?

然后调用
?。获取(0)
。由于null safe
?。
调用,这将计算为一个
Emp?

然后你调用
Emp?
上<代码>
表示将其计算为不可为null的
Emp
或抛出KotlinNullPointerException。它本质上与空安全调用相反

如果您想要空安全,您实际上需要的是继续使用空安全
?。
一旦您有了可空的内容,就会调用整个链,因此您应该替换
。像这样:

var address = if(myEmps?.get(0)?.address?.line1 != null) myEmps?.get(0)?.address!!.line1 else "no address"
第二次使用
可以保留,因为它发生在您的
!=空值
检查,以便您知道
Emp?
不会计算为
空值
。但重复那长长的通话链是很笨拙的。通过使用Elvis运算符
?:
可以消除此if语句,如下所示:

var address = myEmps?.get(0)?.address?.line1 ?: "no address"

你怎么看
是什么?因为它的目标是在再次遇到
null
@a时抛出
NullPointerException
,这里的要点是,如果您注意到,在此之前有一个null安全(?)评估。既然我的对象是空的,而且检查首先会失败,那么为什么下一部分要进行评估呢?谢谢。我想你不明白空安全属性访问是如何工作的。它只是将
null
延迟到链的下游。如果空安全链的任何部分为
null
,则整个过程将为
null
,并添加一个
之后,它将抛出一个
NullPointerException
,因为它是
null
。为什么您认为
get()
不应该得到计算
obj?.call()
在两种情况下都返回null,如果previor
obj
为null,当
call
返回null时,基本上是null传播到下一个语句。可能您的意思是:
myEmps?.get(0)?。让{if(it.address.line1!=null)…}
如果
myEmps
中的任何一个
null
get
返回
null
,您会忽略这些内容。您认为
怎么样是什么?因为它的目标是在再次遇到
null
@a时抛出
NullPointerException
,这里的要点是,如果您注意到,在此之前有一个null安全(?)评估。既然我的对象是空的,而且检查首先会失败,那么为什么下一部分要进行评估呢?谢谢。我想你不明白空安全属性访问是如何工作的。它只是将
null
延迟到链的下游。如果空安全链的任何部分为
null
,则整个过程将为
null
,并添加一个
之后,它将抛出一个
NullPointerException
,因为它是
null
。为什么您认为
get()
不应该得到计算
obj?.call()
在两种情况下都返回null,如果previor
obj
为null,当
call
返回null时,基本上是null传播到下一个语句。可能您的意思是:
myEmps?.get(0)?。让{if(it.address.line1!=null)…}
如果
myEmps
中的任何一个
null
get
返回
null
,则忽略某些内容。这就澄清了问题,非常感谢!这就澄清了,非常感谢!