=================
== The Archive ==
=================

[Kotlin Coroutines] 10장. 예외 처리

개요

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
fun main(): Unit = runBlocking {
    launch {
        launch {
            delay(1000)
            throw Error("Some error")
        }

        launch {
            delay(2000)
            println("Will not be printed")
        }

        launch {
            delay(500) // faster than the exception
            println("Will be printed")
        }
    }

    launch {
        delay(2000)
        println("Will not be printed")
    }
}

코루틴 종료 멈추기

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
fun main(): Unit =
    runBlocking {
        // Don't wrap in a try-catch here. It will be ignored.
        try {
            launch {
                delay(1000)
                throw Error("Some error")
            }
        } catch (e: Throwable) {
            // nope, does not help here
            println("Will not be printed")
        }

        launch {
            delay(2000)
            println("Will not be printed")
        }
    }

SupervisorJob

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
fun main(): Unit =
    runBlocking {
        val scope = CoroutineScope(SupervisorJob())
        scope.launch {
            delay(1000)
            throw Error("Some error")
        }

        scope.launch {
            delay(2000)
            println("Will be printed")
        }

        delay(3000)
    }
// Exception...
// Will be printed

supervisorScope

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
fun main(): Unit =
    runBlocking {
        supervisorScope {
            launch {
                delay(1000)
                throw Error("Some error")
            }

            launch {
                delay(2000)
                println("Will be printed")
            }
        }
        delay(1000)
        println("Done")
    }
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// 이렇게 하면 안 됨
suspend fun sendNotification(
		notifications: List<Notification>,
) = withContext(SupervisorJob()) {
		for (notification in notifications) {
				launch {
						client.send(notification)
				}
		}
}

await

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
private class MyException : Throwable()

suspend fun main() =
    supervisorScope {
        val str1 =
            async<String> {
                delay(1000)
                throw MyException()
            }

        val str2 =
            async {
                delay(2000)
                "Text2"
            }

        try {
            println(str1.await())
        } catch (e: MyException) {
            println(e)
        }

        println(str2.await())
    }

CancellationException 은 부모까지 전파되지 않는다

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
private object MyNonPropagatingException : CancellationException() {
    private fun readResolve(): Any = MyNonPropagatingException
}

suspend fun main(): Unit =
    coroutineScope {
        launch { // 1
            launch { // 2
                delay(2000)
                println("Will not be printed")
            }
            throw MyNonPropagatingException // 3
        }
        launch { // 4
            delay(2000)
            println("Will be printed")
        }
    }

코루틴 예외 핸들러

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
public inline fun CoroutineExceptionHandler(crossinline handler: (CoroutineContext, Throwable) -> Unit): CoroutineExceptionHandler =
    object : AbstractCoroutineContextElement(CoroutineExceptionHandler), CoroutineExceptionHandler {
        override fun handleException(context: CoroutineContext, exception: Throwable) =
            handler.invoke(context, exception)
    }

public interface CoroutineExceptionHandler : CoroutineContext.Element {
    /**
     * Key for [CoroutineExceptionHandler] instance in the coroutine context.
     */
    public companion object Key : CoroutineContext.Key<CoroutineExceptionHandler>

    /**
     * Handles uncaught [exception] in the given [context]. It is invoked
     * if coroutine has an uncaught exception.
     */
    public fun handleException(context: CoroutineContext, exception: Throwable)
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
fun main(): Unit =
    runBlocking {
        val handler =
            CoroutineExceptionHandler { ctx, exception ->
                println("Caught $exception")
            }
        val scope = CoroutineScope(SupervisorJob() + handler)
        scope.launch {
            delay(1000)
            throw Error("Some error")
        }

        scope.launch {
            delay(2000)
            println("Will be printed")
        }

        delay(3000)
    }

요약