協程 exception

根協程 例外

launch

launch就直接拋出例外。
launch需要join()。

1
2
3
4
5
6
7
  @Test
  fun coroutin26() = runTest {
    val job = GlobalScope.launch {
      throw IndexOutOfBoundsException()
    }
    job.join()
  }

async

async需要透過傳回值await(),才可以補捉到例外。
async的await()本身就有join()的功能,會請runTest等待到job1執行完畢才退出。

1
2
3
4
5
6
7
8
9
10
11
@Test
fun coroutin27() = runTest {
  val job1 = GlobalScope.async {
    throw ArithmeticException()
  }
  try {
    job1.await()
  } catch (e: Exception) {
    e.printStackTrace()
  }
}

非根協程 協程中的協程例外

如果是協程中的協程產生例外,不用使用傳回值await(),直接拋出例外。

1
2
3
4
5
6
7
8
9
  @Test
  fun coroutin28() = runTest {
    val job = GlobalScope.launch {
      val child = async {
        throw IllegalArgumentException()
      }
    }
    job.join()
  }
Exception in thread "DefaultDispatcher-worker-2 @coroutine#3" java.lang.IllegalArgumentException

SupervisorJob() 與Job()

Job()

作用域的參數是Job()

CoroutineScope(Job())

子協程有例外,其它子協程也會被取消。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
  @Test
  fun coroutin01() = runTest {
    val scope = CoroutineScope(Job())
    val job1 = scope.launch {
      delay(100)
      throw IllegalArgumentException()
    }
    val job2 = scope.launch {
      delay(1000)
      println("job2 finish")
    }
    joinAll(job1, job2)
  }
}
java.lang.IllegalArgumentException

SupervisorJob()

作用域的參數是SupervisorJob()

CoroutineScope(SupervisorJob())

子協程有例外,其它子協程也會執行,以下執行結果,會顯示job2 finish。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
  @Test
  fun coroutin01() = runTest {
    val scope = CoroutineScope(SupervisorJob())
    val job1 = scope.launch {
      delay(100)
      throw IllegalArgumentException()
    }
    val job2 = scope.launch {
      delay(1000)
      println("job2 finish")
    }
    joinAll(job1, job2)
  }
}
job2 finish

java.lang.IllegalArgumentException

coroutineScope supervisorScope Exception

  • coroutinScope 子協程失敗,其它子協程全取消
  • supervisorScope 子協程失敗,不會影嚮其它子協程
  • supervisorScope 父協程失敗,其它子協程全取消

coroutineScope Exception

job2 拋出Exception(),導致job1被cancel(),不會執行job1 finish。

1
2
3
4
5
6
7
8
9
10
11
12
13
  fun coroutin06() = runTest {
    coroutineScope {
      val job1 = launch {
        delay(400)
        println("job1 finish")
      }
      val job2 = async{
        delay(200)
        println("job2 finish")
        throw IllegalArgumentException()
      }
    }
  }
job2 finish

java.lang.IllegalArgumentException
  at com.example.coroutine.Test01$coroutin06$1$1$job2$1.invokeSuspen

supervisorScope 子協程Exception

子協程job2 拋出Exception(),子協程job1仍會執行完畢。

1
2
3
4
5
6
7
8
9
10
11
12
13
  fun coroutin06() = runTest {
    supervisorScope {
      val job1 = launch {
        delay(400)
        println("job1 finish")
      }
      val job2 = async{
        delay(200)
        println("job2 finish")
        throw IllegalArgumentException()
      }
    }
  }
job2 finish
job1 finish

supervisorScope 父協程Exception

父協程失敗,其它子協程全取消。
child1、child2不會執行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
  @Test
  fun coroutin02() = runTest {
    supervisorScope {
      val child1 = launch {
        println("child1")
      }
      val child2 = launch {
        println("child2")
      }
      // 這是父協程supervisorScope的Exception
      throw IllegalArgumentException()
    }
  }
}
java.lang.IllegalArgumentException

CoroutineExceptionHandler

只能補捉launch的Exception。

只能在supervisorScope、GlobalScope()、CoroutineScope()根協程下補捉作用域中所有Exception、包含作用域下子協程的例外。

GlobalScope

1
2
3
4
5
6
7
8
9
10
@Test
fun coroutin03() = runTest {
  val handler = CoroutineExceptionHandler{ _, exception ->
    println("exception = $exception")
  }
  val scope = GlobalScope.launch(handler){
    throw IllegalArgumentException()
  }
  scope.join()
}
exception = java.lang.IllegalArgumentException

CoroutineScope

1
2
3
4
5
6
7
8
9
10
@Test
fun coroutin04() = runTest {
  val handler = CoroutineExceptionHandler{ _, exception ->
    println("exception = $exception")
  }
  val scope = CoroutineScope(Job()).launch(handler){
    throw IllegalArgumentException()
  }
  scope.join()
}
exception = java.lang.IllegalArgumentException

handler補捉子協程例外

父協程的launch(handler),子協程有Exception也會補捉到Exception

CoroutineScope(Job()).launch(handler)
1
2
3
4
5
6
7
8
9
10
11
12
@Test
fun coroutin04() = runTest {
  val handler = CoroutineExceptionHandler{ _, exception ->
    println("exception = $exception")
  }
  val scope = CoroutineScope(Job()).launch(handler){
    val child = launch {
      throw IllegalArgumentException()
    }
  }
  scope.join()
}

handler無法補捉子協程例外

子協程launch(handler),handler無法補捉到Exception

val child = launch(handler) 
1
2
3
4
5
6
7
8
9
10
11
12
@Test
fun coroutin04() = runTest {
  val handler = CoroutineExceptionHandler{ _, exception ->
    println("exception = $exception")
  }
  val scope = CoroutineScope(Job()).launch{
    val child = launch(handler) {
      throw IllegalArgumentException()
    }
  }
  scope.join()
}

results matching ""

    No results matching ""