首发于公众号: 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
网友评论