协程学习(九)协程简单的使用之异常处理

在上一篇文章中有说过,协程中的异常最初是由下向上抛的,那么我可不可以在 中间层协程中捕获异常呢,下面看一下案例

kotlin 复制代码
@JvmStatic
fun main(array: Array<String>) {
    runBlocking {
        var error=CoroutineExceptionHandler { _, throwable ->
            println("Tsm Error:${throwable}")
        }
       var scope= CoroutineScope(SupervisorJob()+ Dispatchers.IO)
        scope.launch {
            launch {
                launch {
                    launch(error) {
                        launch {
                            throw NullPointerException("我错了")
                        }
                    }
                }
            }
        }
        delay(5*1000)
    }
}

在这里创建了一个新的 CoroutineScope ,指定io线程 与 阻止子协程异常而向导致其他兄弟协程异常退出,最终在最内层的子协程中跑了一个异常,并在倒数第二层的协程中传入了 CoroutineExceptionHandler 想要拦截异常

看一下结果

php 复制代码
Exception in thread "DefaultDispatcher-worker-2 @coroutine#6" java.lang.NullPointerException: 我错了
	at com.tsm.opencv.Tsm$main$1$1$1$1$1$1.invokeSuspend(Tsm.kt:23)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
	at kotlinx.coroutines.internal.LimitedDispatcher$Worker.run(LimitedDispatcher.kt:115)
	at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:100)
	at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:584)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:793)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:697)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:684)
	Suppressed: kotlinx.coroutines.internal.DiagnosticCoroutineContextException: [CoroutineId(2), "coroutine#2":StandaloneCoroutine{Cancelling}@1397bbe2, Dispatchers.IO]

Process finished with exit code 0

发现这个异常还是引起了崩溃,说明这个异常最终只能抛给顶级父协程来处理,中间协程拦截不了

我们再来看一下 async 的表现

typescript 复制代码
@JvmStatic
fun main(array: Array<String>) {
    runBlocking {
        var error=CoroutineExceptionHandler { _, throwable ->
            println("Tsm Error:${throwable}")
        }
        var scope= CoroutineScope(SupervisorJob()+ Dispatchers.IO)

        scope.async{
            async {
                async {
                    async(error) {
                        async {
                            throw NullPointerException("我错了")
                        }
                    }
                }
            }
        }
        delay(5*1000)
    }
}
结果:
Process finished with exit code 0

虽然抛出了异常但是程序没有接受到这个异常,我们使用await 接受一下结果看一下

swift 复制代码
Exception in thread "main" java.lang.NullPointerException: 我错了
	at com.tsm.opencv.Tsm$main$1$1$1$1$1$1.invokeSuspend(Tsm.kt:44)
	at _COROUTINE._BOUNDARY._(CoroutineDebugging.kt:46)
	at com.tsm.opencv.Tsm$main$1.invokeSuspend(Tsm.kt:49)
Caused by: java.lang.NullPointerException: 我错了
	at com.tsm.opencv.Tsm$main$1$1$1$1$1$1.invokeSuspend(Tsm.kt:44)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
	at kotlinx.coroutines.internal.LimitedDispatcher$Worker.run(LimitedDispatcher.kt:115)
	at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:100)
	at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:584)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:793)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:697)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:684)

Process finished with exit code 1

可以看到我们使用await后异常就出现了,这说明 async 虽然也收到了这个异常,但是只有在await后,才会获取异常或者结果从而将他抛出

下面将异常交给顶级父协程来处理看一下结果

先看一下launch 的表现

kotlin 复制代码
@JvmStatic
fun main(array: Array<String>) {
    runBlocking {
        var error=CoroutineExceptionHandler { _, throwable ->
            println("Tsm Error:${throwable}")
        }
       var scope= CoroutineScope(SupervisorJob()+ Dispatchers.IO)
        scope.launch(error) {
            launch {
                launch {
                    launch{
                        launch {
                            throw NullPointerException("我错了")
                        }
                    }
                }
            }
        }
        delay(5*1000)
    }
}
结果:

Tsm Error:java.lang.NullPointerException: 我错了

Process finished with exit code 0

可以看到异常确实被捕获了

再来看看 async

less 复制代码
@JvmStatic
fun main(array: Array<String>) {
    runBlocking {
        var error = CoroutineExceptionHandler { _, throwable ->
            println("Tsm Error:${throwable}")
        }

        var scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
        var job=scope.async(error) {
            throw NullPointerException("我错了")
        }
        job.await()
        delay(1 * 1000)
    }
}
结果:
Exception in thread "main" java.lang.NullPointerException: 我错了
	at com.tsm.opencv.Tsm$main$1$job$1.invokeSuspend(Tsm.kt:42)
	at _COROUTINE._BOUNDARY._(CoroutineDebugging.kt:46)
	at com.tsm.opencv.Tsm$main$1.invokeSuspend(Tsm.kt:44)
Caused by: java.lang.NullPointerException: 我错了
	at com.tsm.opencv.Tsm$main$1$job$1.invokeSuspend(Tsm.kt:42)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
	at kotlinx.coroutines.internal.LimitedDispatcher$Worker.run(LimitedDispatcher.kt:115)
	at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:100)
	at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:584)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:793)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:697)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:684)

Process finished with exit code 1

可以发现在使用async 的过程中即使使用了 CoroutineExceptionHandler 还是抛出了异常,这个是为什么呢, 原因与我们在上面讲的 只有await 的时候才可以获取 这个异常是一样的, 是因为 async 方法只是创建一个协程,但是异常只有调用了await 才能获取,那么在实际开发中该如何处理这种情况呢

1: 在 async 中使用 try catch 捕获异常,保险起见 CoroutineExceptionHandler 还是要在顶级父协程加上的 方式如下

kotlin 复制代码
@JvmStatic
fun main(array: Array<String>) {
    runBlocking {
        var error = CoroutineExceptionHandler { _, throwable ->
            println("Tsm Error:${throwable}")
        }

        var scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
        var job=scope.async(error) {
            try {
                throw NullPointerException("我错了")
            } catch (e: Exception) {
            }
        }
        job.await()
        delay(1 * 1000)
    }
}

2: 为了保险起见在 async 中同样使用 CoroutineExceptionHandler,但是在 await 出try catch

kotlin 复制代码
@JvmStatic
fun main(array: Array<String>) {
    runBlocking {
        var error = CoroutineExceptionHandler { _, throwable ->
            println("Tsm Error:${throwable}")
        }

        var scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
        var job=scope.async(error) {
            throw NullPointerException("我错了")
        }
        job.runCatching { await() }.getOrElse {

        }
        delay(1 * 1000)
    }
}

3: 使用launch 作为顶级父协程 + CoroutineExceptionHandler

kotlin 复制代码
@JvmStatic
fun main(array: Array<String>) {
    runBlocking {
        var error = CoroutineExceptionHandler { _, throwable ->
            println("Tsm Error:${throwable}")
        }

        var scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
        scope.launch(error) {
            var job = async {
                throw NullPointerException("我错了")
            }
            job.await()
        }
        delay(1 * 1000)
    }
}

可以看到使用第三种方法更为的优雅但是具体选择就看个人的喜好了,

相关推荐
huibin14785236926 分钟前
不能识别adb/usb口记录
android·adb
黄林晴3 小时前
Kotlin 2.3.0-Beta1 重磅发布:这些新特性让代码更安全、更高效!
android·kotlin
2501_915921433 小时前
iOS 应用加固与苹果软件混淆全解析 IPA 文件防反编译、混淆加密与无源码加固策略
android·macos·ios·小程序·uni-app·cocoa·iphone
君逸臣劳4 小时前
玩Android Harmony next版,通过项目了解harmony项目快速搭建开发
android·harmonyos
帅锅锅0074 小时前
Android.bp 指南
android
4Forsee4 小时前
【Android】Activity 的生命周期和启动模式
android
撩得Android一次心动5 小时前
Android studio 高效使用
android·ide·android studio
2501_916007476 小时前
iOS 代上架实战指南,从账号管理到使用 开心上架 上传IPA的完整流程
android·macos·ios·小程序·uni-app·cocoa·iphone
2501_915918417 小时前
iOS混淆与IPA文件加固深度解析,从反编译风险到苹果应用安全工程实践
android·macos·ios·小程序·uni-app·cocoa·iphone