这段代码:
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)
...
这种行为对我来说没有意义。异常被捕获和处理,但它仍然作为未处理的异常逃逸到顶层。
这种行为是否被记录和预期?它违反了我对异常处理应该如何工作的所有直觉。
我从Kotlin 论坛上的一个帖子改编了这个问题。
supervisorScope
如果我们不想在协程失败时取消所有协程,则Kotlin 文档建议使用。所以我可以写
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")
}
现在的输出是
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
意味着没有任何全局错误,只是作为业务逻辑的一部分处理的本地化异常。