下面的代码
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()无法正常工作,并且用户没有机会提供输入。
答案 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}},a
和b
。 (毕竟,c
不是数组。)
如果您想用默认值代替null
,a
和b
(如果没有输入),可以将安全调用运算符与{{3 }}。如果不是c
,则返回左侧,否则返回右侧。因此,您可以执行以下操作:
null
在这种情况下,如果val (a, b, c) = readLine()?.split(' ')
?: arrayOf("defA", "defB", "defC")
println("Values are $a, $b, and $c.")
返回一个字符串,则将在其上调用readLine()
;否则,它将使用硬编码数组。
请注意,这仍然不是一个完整的解决方案,因为如果您输入的行少于两个空格,它将无法解决。 (因此,您仍然需要抓住split()
,或明确检查该情况。)
(也许总的来说,最短的解决方案是保留IndexOutOfBoundsException
不变,并更改!!
块以捕获catch
,因此它将捕获Exception
和KotlinNullPointerException
。我不建议这样做,因为它很丑陋:阅读代码的人不清楚,可能会发生什么情况以及打算捕获哪些异常—如果他们发现其他问题,它们可能会隐藏在代码中也导致异常。)