原创

Kotlin异常处理机制

Kotlin也提供了完善的异常处理机制,异常处理机制可以使程序中的异常处理代码和正常业务代码分离,保证程序代码更加优雅,并可以提高程序的健壮性。

Kotlin的异常处理机制可以让程序具有极好的容错性,让程序更加健壮

一、使用try...catch捕获异常

Kotlin的异常处理机制的语法结构如下:

try{
    //业务实现代码
    ...
}catch(e:Exception){
    //异常处理代码
    ...
}
...
finally{
    //可选的finally块
}

整个异常处理流程可包含1个try块、0~N个catch块、0~1个finally块,但是catch块与finally块至少出现其中之一。

如果在执行try块中的业务逻辑代码时出现异常,系统将自动生成一个异常对象,该异常对象被提交给运行时环境,这个过程被称为抛出异常

当运行时环境受到异常对象时,会寻找能处理该异常对象的catch块,如果找到了合适的catch块,就把该异常对象交给该catch块处理,这个过程被称为捕获异常

如果运行时环境找不到捕获异常的catch块,则运行时环境中止,程序也将退出。

import java.io.FileInputStream

fun main(args: Array<String>) {
    try {
        val fis = FileInputStream("a.txt")
        println(fis.read())
    } catch (e: Exception) {
        println("读取文件出现异常")
    }
}

输出结果:

读取文件出现异常

为了保证一定能回收try块中打开的物理资源,异常处理机制提供了finally块。

import java.io.FileInputStream

fun main(args: Array<String>) {
    var fis: FileInputStream? = null
    try {
        fis = FileInputStream("a.txt")
        println(fis.read())
    } catch (e: Exception) {
        println("读取文件出现异常")
    } finally {
        //关闭磁盘文件,回收资源
        fis?.close()
        println("执行finally块里的资源回收!")
    }
}

输出结果:

读取文件出现异常
执行finally块里的资源回收!

通常情况下不要在finally块中使用如return或throw等导致方法中止的语句,一旦在finally块中使用了return或throw语句,就将会导致try块、catch块中的return、throw语句失效。

二、异常类的继承体系

Kotlin提供了kotlin.Throwable类,所有的异常类都是Throwable类的子类。

Kotlin还通过类型别名的方式引入了Java的Error和Exception两个子类,但是Kotlin并没有严格区分错误和异常。

fun main(args: Array<String>) {
    try {
        var a = Integer.parseInt(args[0])
        var b = Integer.parseInt(args[1])
        val c = a / b
        println("您输入的两个数相除的结果是:${c}")
    } catch (ie: IndexOutOfBoundsException) {
        println("数组越界:运行程序时输入的参数个数不够")
    } catch (ne: NumberFormatException) {
        println("数字格式异常:程序只能接收整数参数")
    } catch (ae: ArithmeticException) {
        println("算术异常")
    } catch (e: Exception) {
        println("未知异常")
    }
}

输出结果:

数组越界:运行程序时输入的参数个数不够

上面程序运行时的异常处理逻辑可能有如下几种情形:

  • 如果运行该程序时输入的参数不够,将会发生数组越界异常,运行时环境将调用IndexOutOfBoundsException对应的catch块处理该异常。
  • 如果运行该程序时输入的参数不是数字,而是字母,将发生数字格式异常,运行时环境将调用NumberFormatException对应的catch块处理该异常。
  • 如果运行该程序时输入的第二个参数是0,将发生除0异常,运行时环境将调用ArithmeticException对应的catch块处理该异常。
  • 如果程序运行时出现其他异常,该异常对象总是Exception类或其子类的实例,运行时环境将调用Exception对应的catch块处理该异常。

在进行异常捕获时不仅应该把Exception类对应的catch块放在最后,而且应该把用来捕获所有父类异常的catch块都排在用来捕获子类异常的catch块的后面(先处理小异常,再处理大异常)。

三、访问异常信息

如果程序需要在哎catch块中访问异常对象的相关信息,则可以通过访问catch块后的异常形参来获得。

所有的异常对象都包含了如下几个常用的属性和方法。

  • message:该属性返回该异常的详细描述字符串。
  • stackTrace:该属性返回该异常的跟踪栈信息。
  • printStackTrace():将该异常的跟踪栈信息输出到标准错误输出。
  • printStackTrace(PrintStream s):将该异常的跟踪栈信息输出到指定输出流。
fun main(args: Array<String>) {
    try {
        var fis = FileInputStream("a.txt")
    } catch (ioe: IOException) {
        println(ioe.message)
        ioe.printStackTrace()
    }
}

输出结果:

a.txt (系统找不到指定的文件。)
java.io.FileNotFoundException: a.txt (系统找不到指定的文件。)
	at java.base/java.io.FileInputStream.open0(Native Method)
	at java.base/java.io.FileInputStream.open(FileInputStream.java:196)
	at java.base/java.io.FileInputStream.<init>(FileInputStream.java:139)
	at java.base/java.io.FileInputStream.<init>(FileInputStream.java:94)
	at 0708.AccessExceptionKt.main(AccessException.kt:8)

四、异常处理嵌套

异常处理流程代码可以放在任何能放可执行代码的地方,完整的异常处理流程既可放在try块中,也可放在catch块中,还可放在finally块中,这就形成了异常嵌套。

异常处理嵌套层次太深的话会导致程序可读性降低。

五、try语句时表达式

Kotlin的try语句也是表达式,也可用于对变量赋值。try表达式的返回值是try块中的最后一个表达式的值,或者是被执行的catch块中的最后一个表达式的值,finally块中的内容不会影响表达式的结果。


import java.lang.NumberFormatException

fun main(args: Array<String>) {
    val input= readLine()
    //用try表达式对变量a赋值
    val a:Int?=try{ Integer.parseInt(input)} catch (e:NumberFormatException){null}
    println(a)
}

输出结果:

454
454

如果用户输入的input是合法的整数字符串,程序就会将它转换为整数;如果输入的input不是合法的整数字符串,运行时环境进入执行catch块,因此该try表达式为null。

学海无涯苦作舟

我的微信公众号.jpg

基本语法
  • 作者:HunterArley (联系作者)
  • 发表时间:2019-11-26 10:49
  • 版权声明:本网站部分内容转载于合作站点或其他站点,但都会注明作/译者和原出处。如有不妥之处,敬请指出。
  • 公众号转载:请在文末添加作者公众号二维码