@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)
}
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()
}
异常的传播特性
当一个协程由于一个异常而运行失败时,它会传播这个异常并传递给他的父级。接下来,
父级会
1、取消它自己的子级
2、取消它自己
3、将异常传播并传递给它的父级
很对情况下这不是我们想要的 可以是用
SupervisorJob
@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)
}
这是一个进行中的状态。程序依然在执行
这说明他不会影响它的child协程的执行
换成Job后
val supervisor = CoroutineScope(Job())
程序会执行结束。 和我们上面说的生命周期一样。
也可以是用
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()
}
}
捕获的异常的时机与位置
@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()
}
@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的异常是捕获不到的。内部是不行的外部可以。