- @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的异常是捕获不到的。内部是不行的外部可以。