我用这个测试函数测试了协程的异常处理机制:
suspend fun test(){
supervisorScope {launch(createExceptionHandler(1)) {
coroutineScope {launch(createExceptionHandler(2)) {
supervisorScope {launch { //SUPERVISOR WITH NO HANDLER
coroutineScope {launch(createExceptionHandler(4)) {
coroutineScope {launch(createExceptionHandler(5)) {
throw Exception("Testing")
}}
}}
}}
}}
}}
}
fun createExceptionHandler(i: Int) = CoroutineExceptionHandler { _, throwable ->
"---> exception handler #$i caught: ${throwable}".log()
}
结果:
---> exception handler #2 caught: java.lang.Exception: Testing
我期待处理程序#1捕获异常,但令我惊讶的是,是处理程序#2捕获了异常!
阅读文档时,我希望处理程序#2、#4、#5被完全忽略:
...特别是,所有子协程(在另一个Job的上下文中创建的协程)将它们的异常处理委托给它们的父协程,父协程也委托给父协程,如此类推直到根,所以安装在它们上下文中的CoroutineExceptionHandler永远不会被使用。
我所理解的是,当异常到达根目录或带有异常处理程序的 supervisorScope 时,它就会停止传播。
这个检验函数(2)似乎证实了我的信念:
suspend fun test2(){
supervisorScope {launch(createExceptionHandler(1)) {
supervisorScope {launch(createExceptionHandler(2)) {
supervisorScope {launch {
supervisorScope {launch {
supervisorScope {launch {
throw Exception("Testing")
}}
}}
}}
}}
}}
}
结果:
---> exception handler #2 caught: java.lang.Exception: Testing
我已经在网上阅读了许多关于异常传播和处理的指南,我在这方面相当卡住了...
任何线索都会有帮助,谢谢阅读!
1条答案
按热度按时间dm7nw8vv1#
在第一个例子中,
supervisorScope
启动了一个没有异常处理程序的协程,它实际上继承了外部作用域的异常处理程序。