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

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

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)
    }
}

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

相关推荐
00后程序员张27 分钟前
iOS App 混淆与加固对比 源码混淆与ipa文件混淆的区别、iOS代码保护与应用安全场景最佳实践
android·安全·ios·小程序·uni-app·iphone·webview
CrimsonHu30 分钟前
Android高性能音频:写一个云顶S10强音争霸混音器
android·音视频开发
灿烂阳光g8 小时前
domain_auto_trans,source_domain,untrusted_app
android·linux
低调小一10 小时前
Android传统开发 vs Android Compose vs HarmonyOS ArkUI 对照表
android·华为·harmonyos
雨白10 小时前
Java 多线程指南:从基础用法到线程安全
android·java
00后程序员张11 小时前
详细解析苹果iOS应用上架到App Store的完整步骤与指南
android·ios·小程序·https·uni-app·iphone·webview
程序员江同学12 小时前
ovCompose + AI 开发跨三端的 Now in Kotlin App
android·kotlin·harmonyos
2501_9151063212 小时前
Xcode 上传 ipa 全流程详解 App Store 上架流程、uni-app 生成 ipa 文件上传与审核指南
android·macos·ios·小程序·uni-app·iphone·xcode
消失的旧时光-194313 小时前
Kotlinx.serialization 使用讲解
android·数据结构·android jetpack