我无法删除我的NullPointerException错误

时间:2019-03-10 06:14:27

标签: kotlin nullpointerexception

下面的代码

fun main(args: Array<String>) {
    println("Enter your value : ")
    try{
        val(a, b, c) = readLine()!!.split(' ')
        println("Values are $a $b and $c")
    }catch(ex : IndexOutOfBoundsException){
        println("Invalid. Missing values")
    }
}

在Kotlin游乐场中产生以下错误:

Enter your value:
Exception in thread "main" kotlin.KotlinNullPointerException at FileKt.main(File.kt:4)

我看到了NullPointerException的其他问题,但无法解决。我可能会错过一些内容,因此如果您可以共享有用的链接,这将非常有帮助。由于我是Kotlin的新手,所以如果您更正我的程序,那就太好了。

备注:我也没有关于Java的背景知识,大多数NullPointerException问题都基于Java

编辑1 我尝试了gidds的解决方案,除了一个小故障外,它似乎可以正常工作。由于某些原因,readLine()无法正常工作。

下面的代码

fun main(args : Array <String>){
 val line = readLine()
 try{

    println("Output : $line")

    if (line != null) {
        val(a, b, c) = line.split(' ')
        println("Values are $a $b and $c")
    } else {
             println("No values given...")
    }
  }
catch(ex : IndexOutOfBoundsException){
    println("Invalid. Missing Values...")
}
}

在Kotlin游乐场中产生以下错误:

Output : null
No values given...

我想由于相同的原因,我遇到了先前的错误,即readLine()无法正常工作,并且用户没有机会提供输入。

2 个答案:

答案 0 :(得分:1)

对于readLine()!!,您是说编译器如果返回null,则将崩溃,并抛出NullPointerException。换句话说,必须确保返回值readLine()不为空。详细了解!!运算符here

  

非空断言运算符(!!)将任何值转换为非空   类型,如果该值为空,则引发异常。

您可以使用elvis operator进行空检查,如下所示:

try{
    val(a, b, c) = readLine()?.split(' ')
    println("Values are $a $b and $c")
}catch(ex : IndexOutOfBoundsException){
    println("Invalid. Missing values")
}

答案 1 :(得分:0)

要扩展先前的答案,这是关于如何处理null的问题。

问题是readLine()可以返回null。 (如果到达文件末尾,则会发生这种情况;例如,如果您从文件重定向输入并到达文件的末尾;或者它是从键盘获取输入的,然后按Ctrl + D。)

Kotlin编译器知道这一点。 (Nullability已内置到Kotlin的类型系统中。readLine()返回一个String?-问号表示该值可以为null。)

Kotlin对于空安全性非常谨慎,并且不会让您对如果值为null会失败的值做任何事情。因此,在您的代码中,如果省略!!,则会在以下.上收到错误消息。 (“在类型为String的非空接收器上允许仅安全(?。)或非空断言(!!。)调用吗?”

因此,您必须以某种方式处理null

有效地附加not-null assertion !!可以使编译器更加了解您,并且永远不能为null。这通常是一个坏主意(这就是为什么该操作符设计为看起来难看的原因);在实践中,通常您不会比编译器了解得更多,这将使您大跌眼镜—正如您所发现的!对于您的情况,readLine() 返回null,因此!!运算符抛出了KotlinNullPointerException

因此,您需要一种更好的方法来处理它。

传统方式是显式检查,例如:

val line = readLine()
if (line != null) {
    // Within this block, the compiler knows that line
    // cannot be null.
} else {
    println("No values given.")
}

这是一种很好,清晰,通用的方法。在您的情况下,这可能是最好的方法。 (不过,您仍然需要抓住IndexOutOfBoundsException。)

由于这种方法可能会花费很多时间,因此Kotlin有一些其他工具在特定情况下可能会更好。我认为这里不适合,但出于完整性考虑,我会提及其中一些内容:

其中之一是错误消息中的safe-call operator ?.和更早的答案。仅当值不是null时才进行呼叫;否则,它将直接返回null。这可能确实有用,但是在这种情况下,这不是一个简单的答案,正如您的注释所示:尽管它避免尝试split() null,但是您却无法将其解构为三个值{{ 1}},ab。 (毕竟,c不是数组。)

如果您想用默认值代替nullab(如果没有输入),可以将安全调用运算符与{{3 }}。如果不是c,则返回左侧,否则返回右侧。因此,您可以执行以下操作:

null

在这种情况下,如果val (a, b, c) = readLine()?.split(' ') ?: arrayOf("defA", "defB", "defC") println("Values are $a, $b, and $c.") 返回一个字符串,则将在其上调用readLine();否则,它将使用硬编码数组。

请注意,这仍然不是一个完整的解决方案,因为如果您输入的行少于两个空格,它将无法解决。 (因此,您仍然需要抓住split(),或明确检查该情况。)

(也许总的来说,最短的解决方案是保留IndexOutOfBoundsException不变,并更改!!块以捕获catch,因此它将捕获ExceptionKotlinNullPointerException。我不建议这样做,因为它很丑陋:阅读代码的人不清楚,可能会发生什么情况以及打算捕获哪些异常—如果他们发现其他问题,它们可能会隐藏在代码中也导致异常。)