This code:
fun main() {
runBlocking {
try {
val deferred = async { throw Exception() }
deferred.await()
} catch (e: Exception) {
println("Caught $e")
}
}
println("Completed")
}
结果如下:
Caught java.lang.Exception
Exception in thread "main" java.lang.Exception
at org.mtopol.TestKt$main$1$deferred$1.invokeSuspend(test.kt:11)
...
这种行为对我来说毫无意义.异常被捕获并处理,但它仍然作为未处理的异常逃逸到顶级.
Is this behavior documented and expected? It violates all my intuitions on how exception handling is supposed to work.
我从Kotlin forum的一个帖子里改编了这个问题.
Kotlin文档建议如果我们不想在一个协同路由失败时取消所有协同路由,就使用supervisorScope
.这样我就可以写作了
fun main() {
runBlocking {
supervisorScope {
try {
launch {
delay(1000)
println("Done after delay")
}
val job = launch {
throw Exception()
}
job.join()
} catch (e: Exception) {
println("Caught $e")
}
}
}
println("Completed")
}
The output is now
Exception in thread "main" java.lang.Exception
at org.mtopol.TestKt$main$2$1$job$1.invokeSuspend(test.kt:16)
...
at org.mtopol.TestKt.main(test.kt:8)
...
Done after delay
Completed
这又不是我想要的行为.在这里,一个launch
ed协同路由失败,出现了一个未处理的异常,使其他协同路由的工作无效,但它们不间断地继续进行.
我认为合理的行为是,当协程以不可预见(即,未处理)的方式失败时,分散取消.从await
捕获异常意味着没有任何全局错误,只是作为业务逻辑的一部分处理的本地化异常.