Kotlin中的异常处理与Java或者其他语言中的处理方式相似。一个函数可以以正常方式结束,或者当错误发生的时候抛出异常。函数调用者捕获这个异常并处理它;如果没有,异常重新在调用栈向上抛。
Kotlin中的异常处理语句的基本形式和Java是相似的: java中:
if(0 <= percentage <= 100){
throw new IllegalArgumentException( "A percentage value must be between 0 and 100: $percentage") ;
}
kotlin中:(和java的区别,不必使用new来创建实例)
if (percentage !in 0..100) {
throw IllegalArgumentException( "A percentage value must be between 0 and 100: $percentage")
}
不光如此,kotlin中的throw结构是一个表达式,能作为另一个表达式的一部分使用:
val percentage =
if (number in 0..100)
number
else
throw IllegalArgumentException( //“throw” 是一个表达式
"A percentage value must be between 0 and 100: $number")
这个例子中,如果满足条件,程序的行为正确,percentage会number初始化,否则异常将被抛出,而变量也不会初始化。
就像Java之中,可以用try结构,和catch和finally子句处理异常。
如下,读取指定文件的一行,尝试解析为数字,然后返回一个数字,如果这行不是有效的数字,返回null。
fun readNumber(reader: BufferedReader): Int? { //不必显式地指定这个函数可能抛出的异常
try {
val line = reader.readLine()
return Integer.parseInt(line)
} catch (e: NumberFormatException) { //异常的类型在右边
return null
} finally { //finally就像在Java一样的
reader.close()
}
}
val reader = BufferedReader(StringReader("239"))
println(readNumber(reader))
//239
java中:
public int readNumber(BufferedReader reader) throws IOException{ //显式地指定这个函数可能抛出的异常
try {
String line = reader.readLine()
return Integer.parseInt(line)
} catch (NumberFormatException e) {
return null
} finally {
reader.close()
}
}
从对比中我们可以看出kotlin和Java最大的不同是不需要throws子句。在java中,这种异常必须显示的处理,必须声明你的函数可能抛出的所有受检异常。 如果调用另一个函数,需要处理这个函数的受检异常,或者声明你的函数可能抛出的这些异常。
和其他现代JVM语言,Koltin不区别受检查和不受检查的异常。你需要指定一个函数抛出的异常,你可以也可以不处理这些异常。这个设计决定是基于Java中使用受检查异常的实践。经验表明,Java规则常常需要很多无意义的代码从新抛出或者忽略异常,而且这些规则不能总是保护你免受坑你发生的错误。
在上面的例子中,NumberFormatException是一个不受检查的异常。所以Java编译器不会强迫你捕获这个异常,你可以很容易的看见运行时的异常。这相当令人遗憾,因为不有效的输入数据是经常的事情,应该更优雅的处理。同时,BufferedReader.close方法也能抛出一个IOException异常,这是个需要处理的受检查的异常。如果关闭一个流失败了,大部分代码不能采取任何有意义的行动,所以需要从close方法捕获异常的代码基本是样板代码。
为了显示Java和Kotlin直接一个重要区别,让我们稍微改变下这个例子。移除fianlly部分(因为你已经知道这个怎么工作),然后加一些代码打印从这个文件读取的数字。
fun readNumber(reader: BufferedReader) {
val number = try {
Integer.parseInt(reader.readLine()) //成为try表达式的值
} catch (e: NumberFormatException) {
return
}
println(number)
}
val reader = BufferedReader(StringReader("not a number"))
readNumber(reader)//没有打印任何数字
Kotlin中try关键词,就像if和when,引进了一个表达式,你可以把它的值赋值给一个变量。不像if,你一直需要把语句保函在花括号中。就像其他语句,如果包涵多个表达式,try表达式的值是最后一个表达式的值。在这个例子中,在catch代码块中有return语句,所以这个函数在catch代码块后不会再进行。如果你想继续这个执行,catch语句也需要一个值,这个值是最后表达式的值:
fun readNumber(reader: BufferedReader) {
val number = try {
Integer.parseInt(reader.readLine()) //没有异常发生时使用这个值
} catch (e: NumberFormatException) {
null //异常发生时使用null值
}
println(number)
}
val reader = BufferedReader(StringReader("not a number"))
readNumber(reader)//异常被抛出,所以函数打印null
//null
如果一个try代码块执行一切正常,代码块中最后一个表达式就是结果。如果捕获到一个异常,那么cache代码块中最后一个表达式就是结果。