Kotlin异常处理(2)捕获异常

  • try-catch 语句
  • try-catch 表达式
  • catch 代码块
  • try-catch 语句嵌套

一、try-catch 语句

捕获异常是通过使用 try-catch 语句实现的,最基本的 try-catch 语句语法如下:

try {
    // 可能会发生异常的代码
} catch (throwable: Throwable) {
    // 捕获到异常的处理
}
  • try 代码块
    try 代码块中应该包含执行过程中可能会出现异常的语句。
  • catch 代码块
    每个 try 代码块 可以伴随一个或多个 catch 代码块,用于处理 try 代码块 中可能发生的多种异常。catch (throwable: Throwable) 语句中的 throwable 是捕获异常对象,throwable 必须是 Throwable 的子类,异常对象throwable 的作用域在该catch 代码块中。
  • try-catch 示例:
fun divide(number: Int, divisor: Int): Int {
    try {
        return number / divisor
    } catch (e: ArithmeticException) {
        println("message : ${e.message}")
        println("toString() : ${e.toString()}")
        println("printStackTrace() 输出堆栈信息:")
        println(e.printStackTrace())
    }
    return 0
}

fun main(args: Array?) {
    val divisor = 0
    val result = divide(5, divisor)
    println("divide(5, $divisor) = $result")
}

运行结果如下:

I: message : divide by zero
I: toString() : java.lang.ArithmeticException: divide by zero
I: printStackTrace() 输出堆栈信息:
W: java.lang.ArithmeticException: divide by zero
W:     at cn.ak.kotmodule.WwwwKt.divide(wwww.kt:16)
W:     at cn.ak.kotmodule.WwwwKt.main(wwww.kt:28)
W:     at cn.ak.kot.MainActivity$onCreate$1.onClick(MainActivity.kt:19)
W:     at android.view.View.performClick(View.java:6597)
W:     at android.view.View.performClickInternal(View.java:6574)
W:     at android.view.View.access$3100(View.java:778)
W:     at android.view.View$PerformClick.run(View.java:25885)
W:     at android.os.Handler.handleCallback(Handler.java:873)
W:     at android.os.Handler.dispatchMessage(Handler.java:99)
W:     at android.os.Looper.loop(Looper.java:193)
W:     at android.app.ActivityThread.main(ActivityThread.java:6669)
W:     at java.lang.reflect.Method.invoke(Native Method)
W:     at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
W:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
I: kotlin.Unit
I: divide(5, 0) = 0

二、try-catch 表达式

在 kotlin 中,很多情况下 try-catch语句被 try-catch 表达式代替,kotlin 中提倡使用 try-catch 表达式,这样会使代码更简洁。

fun divide(number: Int, divisor: Int): Int = try {
    number / divisor
} catch (e: ArithmeticException) {
    0
}

三、多 catch 代码块

如果 try 代码块中有很多语句发生异常,而且发生的异常种类又很多,那么可以在 try 后面跟随多个 catch 代码块。多个 catch 代码块语法如下:

try {
    // 可能会发生异常的代码
} catch (throwable: Throwable) {
    // 捕获到异常的处理
} catch (throwable: Throwable) {
    // 捕获到异常的处理
} catch (throwable: Throwable) {
    // 捕获到异常的处理
} ......

在多个 catch 代码块的情况下,当一个 catch 代码块捕获到一个异常时,其他的 catch 代码块就不再进行匹配。

注意:当捕获的多个异常类之间存在父子关系时,捕获异常顺序与 catch 代码块顺序有关系。一般先捕获子类,后捕获父类,否则子类永远捕获不到。

  • 多 catch 示例代码:
fun main(args: Array?) {
    val date = readDataFromFile()
    println("读取的日期 = $date")
}

fun readDataFromFile() : Date? {
    val df = SimpleDateFormat("yyyy-MM-dd")
    try {
        val fileIs = FileInputStream("readme.txt") // 1️⃣
        val isr = InputStreamReader(fileIs)
        val br = BufferedReader(isr)
        // 读取文件中的第一行数据
        val str = br.readLine() ?: return null // 2️⃣
        return df.parse(str)
    } catch (e: FileNotFoundException) {
        println("处理 FileNotFoundException ...")
        e.printStackTrace()
    } catch (e: IOException) {
        println("处理 IOException ...")
        e.printStackTrace()
    } catch (e: ParseException) {
        println("处理 ParseException ...")
        e.printStackTrace()
    }
    return null
}

运行结果如下:

I: 处理 FileNotFoundException ...
W: java.io.FileNotFoundException: readme.txt (No such file or directory)
W:     at java.io.FileInputStream.open0(Native Method)
W:     at java.io.FileInputStream.open(FileInputStream.java:231)
W:     at java.io.FileInputStream.(FileInputStream.java:165)
W:     at java.io.FileInputStream.(FileInputStream.java:112)
W:     at cn.ak.kotmodule.WwwwKt.readDataFromFile(wwww.kt:29)
W:     at cn.ak.kotmodule.WwwwKt.main(wwww.kt:22)
W:     at cn.ak.kot.MainActivity$onCreate$1.onClick(MainActivity.kt:19)
W:     at android.view.View.performClick(View.java:6597)
W:     at android.view.View.performClickInternal(View.java:6574)
W:     at android.view.View.access$3100(View.java:778)
W:     at android.view.View$PerformClick.run(View.java:25885)
W:     at android.os.Handler.handleCallback(Handler.java:873)
W:     at android.os.Handler.dispatchMessage(Handler.java:99)
W:     at android.os.Looper.loop(Looper.java:193)
W:     at android.app.ActivityThread.main(ActivityThread.java:6669)
W:     at java.lang.reflect.Method.invoke(Native Method)
W:     at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
W:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
I: 读取的日期 = null

上面代码是从文件readme.txt读取字符串,然后解析成为日期。其中使用到 I/O 流对文件进行读取。try 代码块中的第1️⃣行代码调用 FileInputStream 构造函数会发生FileNotFoundException异常。第2️⃣行代码调用BufferedReader输入流的readLine()函数会发生IOException异常。而FileNotFoundException异常是IOException异常的子类,应该先捕获FileNotFoundException异常,后捕获IOException异常。

  • 如果将 FileNotFoundExceptionIOException 的捕获顺序调换,代码如下:
fun readDataFromFile(): Date? {
    val df = SimpleDateFormat("yyyy-MM-dd")
    try {
        val fileIs = FileInputStream("readme.txt")
        val isr = InputStreamReader(fileIs)
        val br = BufferedReader(isr)
        // 读取文件中的第一行数据
        val str = br.readLine() ?: return null
        return df.parse(str)
    } catch (e: IOException) {
        println("处理 IOException ...")
        e.printStackTrace()
    } catch (e: FileNotFoundException) {
        println("处理 FileNotFoundException ...")
        e.printStackTrace()
    } catch (e: ParseException) {
        println("处理 ParseException ...")
        e.printStackTrace()
    }
    return null
}

运行结果如下:

I: 处理 IOException ...
W: java.io.FileNotFoundException: readme.txt (No such file or directory)
W:     at java.io.FileInputStream.open0(Native Method)
W:     at java.io.FileInputStream.open(FileInputStream.java:231)
W:     at java.io.FileInputStream.(FileInputStream.java:165)
W:     at java.io.FileInputStream.(FileInputStream.java:112)
W:     at cn.ak.kotmodule.WwwwKt.readDataFromFile(wwww.kt:28)
W:     at cn.ak.kotmodule.WwwwKt.main(wwww.kt:21)
W:     at cn.ak.kot.MainActivity$onCreate$1.onClick(MainActivity.kt:19)
W:     at android.view.View.performClick(View.java:6597)
W:     at android.view.View.performClickInternal(View.java:6574)
W:     at android.view.View.access$3100(View.java:778)
W:     at android.view.View$PerformClick.run(View.java:25885)
W:     at android.os.Handler.handleCallback(Handler.java:873)
W:     at android.os.Handler.dispatchMessage(Handler.java:99)
W:     at android.os.Looper.loop(Looper.java:193)
W:     at android.app.ActivityThread.main(ActivityThread.java:6669)
W:     at java.lang.reflect.Method.invoke(Native Method)
W:     at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
W:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
I: 读取的日期 = null

由此可见顺序颠倒后,FileNotFoundException 异常处理永远不会执行。

四、try-catch 语句嵌套

kotlin 提供的 try-catch语句是可以任意嵌套的。如下:

fun readDataFromFile() : Date? {
    val df = SimpleDateFormat("yyyy-MM-dd")
    try {
        val fileIs = FileInputStream("readme.txt")
        val isr = InputStreamReader(fileIs)
        val br = BufferedReader(isr)
        
        try {
            // 读取文件中的第一行数据
            val str = br.readLine() ?: return null
            return df.parse(str)
        } catch (e: ParseException) {
            println("处理 ParseException ...")
            e.printStackTrace()
        }
    } catch (e: FileNotFoundException) {
        println("处理 FileNotFoundException ...")
        e.printStackTrace()
    } catch (e: IOException) {
        println("处理 IOException ...")
        e.printStackTrace()
    }
    return null
}

程序执行时内层如果发生异常,首先由内层 catch 进行捕获,如果捕获不到,则有外层 catch 捕获。

注意:try-catch不仅可以嵌套在 try 代码块中,还可以嵌套在 catch 代码块finally 代码块中。try-catch 嵌套会使程序流程变的复杂,如果能用多 catch 捕获异常,尽量不要使用 try-catch 嵌套。要梳理好程序的流程再考虑 try-catch 嵌套的必要性。

下载说明:
1、本站所有资源均从互联网上收集整理而来,仅供学习交流之用,因此不包含技术服务请大家谅解!
2、本站不提供任何实质性的付费和支付资源,所有需要积分下载的资源均为网站运营赞助费用或者线下劳务费用!
3、本站所有资源仅用于学习及研究使用,您必须在下载后的24小时内删除所下载资源,切勿用于商业用途,否则由此引发的法律纠纷及连带责任本站和发布者概不承担!
4、本站站内提供的所有可下载资源,本站保证未做任何负面改动(不包含修复bug和完善功能等正面优化或二次开发),但本站不保证资源的准确性、安全性和完整性,用户下载后自行斟酌,我们以交流学习为目的,并不是所有的源码都100%无错或无bug!如有链接无法下载、失效或广告,请联系客服处理!
5、本站资源除标明原创外均来自网络整理,版权归原作者或本站特约原创作者所有,如侵犯到您的合法权益,请立即告知本站,本站将及时予与删除并致以最深的歉意!
6、如果您也有好的资源或教程,您可以投稿发布,成功分享后有站币奖励和额外收入!
7、如果您喜欢该资源,请支持官方正版资源,以得到更好的正版服务!
8、请您认真阅读上述内容,注册本站用户或下载本站资源即您同意上述内容!
原文链接:https://www.dandroid.cn/12760,转载请注明出处。
0

评论0

显示验证码
没有账号?注册  忘记密码?