在Kotlin中到底是什么为空,为什么我不能用它引起NPE?

时间:2019-08-08 20:05:36

标签: kotlin

查看以下在Kotlin REPL中运行的代码:

>>> null.takeIf({1==2})
res4: kotlin.Nothing? = null

为什么这不会导致NullPointerException?

2 个答案:

答案 0 :(得分:7)

您的代码不会导致NullPointerException,因为takeIf是扩展函数。
扩展函数被转换为方法接收器,第一个参数是您在其上调用函数的对象。

因此,您可能想知道为什么下面的函数没有抛出NullPointerException而不是null.takeIf { false }(简化您的示例):

fun <T> takeIf(me: T, predicate: (T) -> Boolean): T? {
    ...
}

好吧,为此,我们需要研究takeIf()的实现(删除注释和协定):

public inline fun <T> T.takeIf(predicate: (T) -> Boolean): T? {
    return if (predicate(this)) this else null
}

因此,如果您的谓词为假(例如在您的示例中,1==2),它将短路并返回null。

如果是true,该怎么办?我们最终会得到一个NullPointer吗?

不是:

val nothing: Nothing? = null.takeIf {
    true
}

答案 1 :(得分:0)

科特林针对类型的设计方法旨在有目的地消除NPE。如文档所示,可能触发条件的条件仅限于

  • 显式调用以引发NullPointerException();
  • 用法!如下所述的运算符;
  • 关于初始化的某些数据不一致,例如:
    • 构造函数中可用的未初始化的this传递并在某处使用(“泄漏此”);
    • 超类构造函数调用一个open成员,该成员在派生类中的实现使用未初始化状态; <​​/ li>
  • Java互操作:
    • 尝试访问平台类型为null的成员;
    • 用于Java互操作的泛型类型具有不正确的可空性,例如一段Java代码可能会将空值添加到Kotlin MutableList中,这意味着应该使用MutableList进行操作;
    • 由外部Java代码引起的其他问题。
  

第三个选项适用于NPE爱好者:非空声明运算符   (!!)将任何值转换为非null类型,并在出现以下情况时引发异常   该值为空。我们可以写b !!,这将返回非null   b的值(例如,在我们的示例中为String),或者如果b为   空:

     

val l = b!!.length

     

因此,如果您需要NPE,可以拥有它,但是   必须明确要求它,并且它不会突然出现。

因此您的代码行为符合预期。请参阅链接以获取更多信息

https://kotlinlang.org/docs/reference/null-safety.html