首發于公眾號: DSGtalk1989
32.協程異常處理
-
異常的傳播
launch
和actor
構建器是不傳播異常的,async
和produce
是傳播異常的。這里的傳播說的更容易理解一點叫做,往外拋,即不傳播異常就是在本協程中自己消化,異常發生在本協程所在的線程;傳播異常表示不在本協程所在線程發生,異常直接往外拋到啟動該協程所在的線程。我們看如下demo
val job = GlobalScope.launch {
println("${Thread.currentThread().name} : Throwing exception from launch")
throw IndexOutOfBoundsException()
}
job.join()
println("Joined failed job")
val deferred = GlobalScope.async {
println("${Thread.currentThread().name} : Throwing exception from async")
throw ArithmeticException()
}
deferred.await()
println("Unreached")
控制臺打印
DefaultDispatcher-worker-1 : Throwing exception from launch
Exception in thread "DefaultDispatcher-worker-1" java.lang.IndexOutOfBoundsException
at salamanca.DestructTestKt$main$1$job$1.invokeSuspend(DestructTest.kt:52)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:32)
at kotlinx.coroutines.DispatchedTask.run(Dispatched.kt:233)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:594)
at kotlinx.coroutines.scheduling.CoroutineScheduler.access$runSafely(CoroutineScheduler.kt:60)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:742)
Joined failed job
DefaultDispatcher-worker-1 : Throwing exception from async
Exception in thread "main" java.lang.ArithmeticException
at salamanca.DestructTestKt$main$1$deferred$1.invokeSuspend(DestructTest.kt:58)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:32)
at kotlinx.coroutines.DispatchedTask.run(Dispatched.kt:233)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:594)
at kotlinx.coroutines.scheduling.CoroutineScheduler.access$runSafely(CoroutineScheduler.kt:60)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:742)
我們看到兩個異常分別在協程的線程和主線程中拋出來一個由于在協程內,所以不會造成主線程異常,一個在主線程,所以直接跪了。
-
CoroutineExceptionHandler
所以針對上面這種情況,我們應該怎么辦,比如我們想要去catch
一下,針對上面的launch
和await
方法,我們包裹了try catch
如下
try{
job.join()
}catch (e : Exception){
println(e.toString())
}
try{
deferred.await()
}catch (e : Exception){
println(e.toString())
}
發現await
是可以捕捉的,join
無法用try catch
捕捉。所以針對這種不傳播異常的,我們應該怎么去捕捉它呢。CoroutineExceptionHandler
登場。
我們將上面的代碼作如下改動
val handler = CoroutineExceptionHandler { _, exception ->
println("Caught $exception")
}
val job = GlobalScope.launch(handler) {
println("${Thread.currentThread().name} : Throwing exception from launch")
throw IndexOutOfBoundsException()
}
job.join()
打印如下,舒坦。
DefaultDispatcher-worker-1 : Throwing exception from launch
Caught java.lang.IndexOutOfBoundsException
Kotlin學習筆記之 13 基礎操作符run、with、let、also、apply