这一节我们说说Kotlin中的异常。
我们知道,在Java中,异常是一个绕不过的话题,说到异常,最先想到的就是try...catch...finally
,在Kotlin中也是同样的,使用方式几乎是不变的,但是也有一些小小的变动。这里我们还是以往的惯例,先放Java代码,再上Kotlin代码。
Java代码
public int readNumber(BufferedReader reader) throws IOException {
int result = 0;
String line = reader.readLine();
result = Integer.parseInt(line);
reader.close();
return result;
}
上面的代码readLine()
方法会抛出IOException
,这是一个受检查异常,必须要显式处理,要么在方法声明上抛出,要么在内部捕获处理。其实代码里面的parseInt()
方法也会抛出一个运行时异常,Java是不强制要求我们捕获处理运行时异常的,但这里我们为了和后面的内容配合讲解,处理一下这个异常。
修改后的代码是这样。
Java代码
public int readNumber(BufferedReader reader) throws IOException {
int result = 0;
String line = reader.readLine();
try {
result = Integer.parseInt(line);
}catch (NumberFormatException e){
e.printStackTrace();
result = -1;
}finally {
if (reader != null){
reader.close();
}
}
return result;
}
这里使用try...catch...finally
来改善了一下代码。在Java中,一个函数可以正常结束,也会在出现错误的时候抛出异常,方法的调用者可以捕获这个异常并处理它,如果没有被处理,异常会沿着调用栈再次抛出。
在Kotlin中异常处理机制是相似的,但与Java中不同的是throw
是一个表达式,可以作为另一个表达式的一部分使用。我们看看下面的代码。
Kotlin代码
fun test(){
val n = 1;
val res = if (n in 0..100){
n
}else{
throw IllegalArgumentException("error")
}
println(res)
}
这里说一下,前面的内容也说过if
也是表达式,上面的代码,如果n的值在0-100直接则res的值初始化为n的值,如果不是,抛出一个异常,res的值不初始化。与我们以前的代码一样,与Java语言不同,抛出的异常不需要使用new
。
我们在开始给出了一个Java中的try...catch...finally
的例子,这里我们再使用Kotlin代码实现一下,对比一下两者的差异。
Kotlin代码
fun readNumber(reader: BufferedReader): Int{
var result = 0
val line = reader.readLine()
try {
result = Integer.parseInt(line)
} catch (e: NumberFormatException) {
e.printStackTrace()
result = -1
} finally {
reader.close()
}
return result
}
上面的代码有几点需要注意。
1. 正如前面一直在说的,函数返回值类型是写在最后,用:
分割。
2. 你会发现Kotlin中不需要显式在方法声明上声明抛出的IOException
。
3. 变量的声明也是变量名:变量类型
的格式。
在Kotlin中不再区分受检查异常和不受检查异常。原因在于有时候比如我们的文件关闭出现错误的异常,除了看到这个异常,其实我们也做不了什么,Kotlin则直接将这种代码去掉了。
可能有的人还有疑问,在前面的java代码的finally
块中有这样的的判空代码
if (reader != null){
reader.close();
}
为什么在Kotlin中消失了?这是因为在Kotlin中声明函数参数类型时,如果这样写reader: BufferedReader
,表示这是一个不可空值,如果要声明为可空值可以这样写reader: BufferedReader?
,这样就需要在close前判空了。
前面我们说了throw
作为表达式,其实try也是一个表达式,我们可以将try
的值赋值给一个变量。我们继续该一下上面的代码。
Kotlin代码
fun readNumber(reader: BufferedReader): Int?{
var result = 0
val line = reader.readLine()
result = try {
Integer.parseInt(line)
} catch (e: NumberFormatException) {
e.printStackTrace()
-1
} finally {
reader.close()
}
return result
}
你会发现代码又变少了,这里我们先补充一条规则才能理解上面的代码。
当try
作为表达式时,如果try块执行正常,则try块中最后一个表达式就是结果,如果抛出异常进入catch
块,则catch块中最后一个表达式的值就是结果。
知道了这条规则是不是上面的代码就好理解了
异常机制的出现是为了让我写出更加健壮的代码,在Kotlin中对Java的异常处理机制进行了一些改进和完善,让我们用更简洁的方式处理异常。