Kotlin I';我无法删除我的NullPointerException错误

Kotlin I';我无法删除我的NullPointerException错误,kotlin,nullpointerexception,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. Mi

下面的代码

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")
    }
}
我看到了其他与NullPointerException有关的问题,但我无法解决它。我可能会错过一些,所以如果你能分享有用的链接,这将是非常有帮助的。因为我是Kotlin的新手,如果你能纠正我的程序,那就太棒了

备注:我对java也没有任何背景,大多数NullPointerException问题都是基于java的

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

下面的代码

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")
    }
}
我想我之前的错误也是出于同样的原因,即readLine()工作不正常,用户没有机会提供输入。

使用
readLine(),您是在告诉编译器,如果返回null,则会导致NullPointerException崩溃。另一方面,必须确保
readLine()
的返回值不为null。阅读更多关于
操作员

NOTNULL断言运算符(
!!
)将任何值转换为非空值 如果值为null,则键入并引发异常

您可以使用如下方式进行空检查:

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

要扩展前面的答案,这是关于如何处理
null
s

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

Kotlin编译器知道这一点。(可空性内置于Kotlin的类型系统中。
readLine()
返回一个
字符串?
-问号表示该值可以是
null

Kotlin对空安全性非常小心,不会让您对
null
的值执行任何可能失败的操作。因此,在您的代码中,如果您忽略
,则在以下
中出现错误('String类型的不可空接收器上只允许安全(?)或非空断言(!!.)调用')

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

添加运算符可以有效地向编译器保证您更了解它,并且它永远不能为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还有一些其他工具在特定情况下可以更好。我认为这里没有合适的工具,但为了完整性,我会提到一些:

其中之一是错误消息中给出的值和前面的答案。只有当值不是
null
时,才会进行调用;否则,它将直接返回
null
。这可能非常有用,但正如您的评论所示,在这种情况下,这并不是一个简单的答案:尽管它避免尝试
split()
null
分解为
a
b
c
(毕竟,
null
不是数组。)

如果要将默认值替换为
a
b
c
(如果没有输入),则可以将safe call运算符与一起使用。如果safe call运算符不为
null
,则返回左侧,否则返回右侧。因此,您可以执行以下操作,例如:

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

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


(也许最短的整体解决方案是保持
!!
不变,并将
catch
块更改为catch
Exception
,这样它将捕获
KotlinNullPointerException
以及
IndexOutOfBoundsException
。我不建议这样做,因为它很难看:任何读者都不清楚g代码可能发生的情况以及您打算捕获的异常-如果它们也导致了异常,则可能会隐藏代码中的其他问题。)

上述代码在Kotlin Playerd中显示了一个错误,如:------->{调用destructuring declaration initializer的'component1()'函数所需的非nullable值。}---------“组件2”和“组件3”还有两个这样的错误。
val line = readLine()
if (line != null) {
    // Within this block, the compiler knows that line
    // cannot be null.
} else {
    println("No values given.")
}
val (a, b, c) = readLine()?.split(' ')
              ?: arrayOf("defA", "defB", "defC")
println("Values are $a, $b, and $c.")