You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何Kotlin协程需调用join()才能让try-catch捕获未处理异常?

协程异常捕获差异解析:为什么只有调用join()时catch才生效?

先看你提供的代码:

fun caughtExceptionTest1() {
  runBlocking {
    try {
      launch { throwException() }.join()
    } catch (e: Exception) {
      // This prints
      print("caught Exception")
    }
  }
}

fun caughtExceptionTest2() {
  runBlocking {
    try {
      launch { throwException() }
    } catch (e: Exception) {
      // This does not print
      print("caught Exception")
    }
  }
}

核心原因在于协程异常的传播时机和join()的行为特性:

  • caughtExceptionTest1 生效的原因:
    launch创建的子协程抛出异常后,该异常会被协程框架暂存。当你调用join()时,当前协程会阻塞等待子协程执行完毕,此时框架会把暂存的异常重新抛到join()的调用位置,刚好落在外层try代码块的范围内,所以catch块能捕获到这个异常并执行打印逻辑。

  • caughtExceptionTest2 不生效的原因:
    这里只调用launch创建子协程,没有调用join(),当前的runBlocking协程不会等待子协程执行。try-catch块会直接执行完毕——此时子协程可能还没开始执行,或者刚抛出异常,但异常的传播路径是直接通知父协程(runBlocking),而父协程的try-catch已经执行结束了,自然没机会捕获到这个异常。

额外补充:
launch启动的协程属于非阻塞启动,如果不主动调用join()/await()等待,父协程会继续执行后续代码。而launch的未捕获异常默认会向父协程传播,但只有当父协程在等待子协程完成的代码路径上,异常才会被抛到当前执行流中,让try-catch有机会处理。如果父协程已经走完了try块,后续子协程抛出的异常只会导致父协程被取消,但无法触发已经执行过的catch块。

内容的提问来源于stack exchange,提问作者fness

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 05:24:54