協程 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()
}