为何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
相关产品推荐
相关产品推荐

