@Test
fun `test exception propagation`() = runBlocking<Unit> {
val job = GlobalScope.launch {
try {
throw IndexOutOfBoundsException()
} catch (e: Exception) {
println("Caught: ${e}}")
}
}
job.join()
val deferred = GlobalScope.async {
throw ArithmeticException()
}
try {
deferred.await()
} catch (e: Exception) {
println("Caught: ${e}}")
}

delay(1000)

}

Android 协程 异常捕获 异常的传播特性_android

launch的异常是再方法体里面 无论是否执行 


job.join()


都会报错/

而async的异常则是需要在await的时候才会抛出来

不执行则不会抛出来异常

@Test
fun `test exception propagation2`() = runBlocking<Unit> {
val scope = CoroutineScope(Job())
val job = scope.launch {
//非根协程的异常 launch就会立即抛出异常
async {
throw IllegalArgumentException()
}
}
job.join()

}

Android 协程 异常捕获 异常的传播特性_java_02

 异常的传播特性

当一个协程由于一个异常而运行失败时,它会传播这个异常并传递给他的父级。接下来,

父级会

1、取消它自己的子级

2、取消它自己

3、将异常传播并传递给它的父级

很对情况下这不是我们想要的 可以是用

SupervisorJob

Android 协程 异常捕获 异常的传播特性_java_03

@Test
fun `test SupervisorJob`() = runBlocking<Unit> {
val supervisor = CoroutineScope(SupervisorJob())
val job1 = supervisor.launch {
delay(1000)
println("child 1")
throw IllegalArgumentException()
}

val job2 = supervisor.launch {
try {
delay(Long.MAX_VALUE)
} finally {
println("child 2 finished")
}
}
joinAll(job1, job2)


}

Android 协程 异常捕获 异常的传播特性_android_04

 这是一个进行中的状态。程序依然在执行

这说明他不会影响它的child协程的执行

换成Job后

val supervisor = CoroutineScope(Job())

Android 协程 异常捕获 异常的传播特性_抛出异常_05

 程序会执行结束。 和我们上面说的生命周期一样。

也可以是用


supervisorScope 效果是和SupervisorJob 一样的


@Test
fun `test SupervisorScope`() = runBlocking<Unit> {
supervisorScope {
launch {
delay(1000)
println("child 1")
throw IllegalArgumentException()
}

launch {
try {
delay(Long.MAX_VALUE)
} finally {
println("child 2 finished")
}
}


}


}

但是如果父协程的抛出了异常。子协程也会跟着退出

@Test
fun `test SupervisorScope2`() = runBlocking<Unit> {
supervisorScope {
try {
val child = launch {
println("The child is sleeping")
delay(Long.MAX_VALUE)
}
} finally {
println("The child is over")

}
yield()
println("Throwing an exception from the scope")
throw AssertionError()


}


}

Android 协程 异常捕获 异常的传播特性_开发语言_06

 捕获的异常的时机与位置

Android 协程 异常捕获 异常的传播特性_抛出异常_07

 

@Test
fun `test CoroutineExceptionHandler`() = runBlocking<Unit> {
val coroutineExceptionHandler = CoroutineExceptionHandler { _, exception ->
println("Caught $exception")
}
val job1 = GlobalScope.launch(coroutineExceptionHandler) {
throw AssertionError()
}
val job2 = GlobalScope.async(coroutineExceptionHandler) {
throw ArithmeticException()
}
job1.join()
job2.await()

}

Android 协程 异常捕获 异常的传播特性_Test_08

 

@Test
fun `test CoroutineExceptionHandler2`() = runBlocking<Unit> {
val coroutineExceptionHandler = CoroutineExceptionHandler { _, exception ->
println("Caught $exception")
}
val scope = CoroutineScope(Job())
val job = scope.launch(coroutineExceptionHandler) {
launch {
throw IllegalArgumentException()
}
}
job.join()

}

@Test
fun `test CoroutineExceptionHandler3`() = runBlocking<Unit> {
val coroutineExceptionHandler = CoroutineExceptionHandler { _, exception ->
println("Caught $exception")
}
val scope = CoroutineScope(Job())
val job = scope.launch() {
launch(coroutineExceptionHandler) {
throw IllegalArgumentException()
}
}
job.join()

}

test CoroutineExceptionHandler2的异常是可以捕获到的

test CoroutineExceptionHandler3的异常是捕获不到的。内部是不行的外部可以。