Sobes.tech
Middle

Co se stane s korutou, když dojde k výjimce?

sobes.tech AI

Odpověď od AI

Při výskytu výjimky uvnitř korutiny závisí způsob jejího zpracování na typu výjimky (a nastavení dispatcheru/kontextu).

  • Neřízená výjimka: Pokud je výjimka nezachycena uvnitř korutiny, propaguje se vzhůru po hierarchii korutin až k nejbližšímu rodičovskému Job (nebo CoroutineScope). Chování závisí na typu Job:

    • Job: Ve výchozím nastavení, pokud dojde k výjimce v podřízené korutině, rodičovský Job je zrušen, což vede ke zrušení všech jeho ostatních podřízených korutin. Výjimka je přenášena výše.
    • SupervisorJob: Rodičovský SupervisorJob není zrušen při výskytu výjimky v podřízené korutině. Zrušena je pouze samotná korutina, ve které došlo k výjimce. To je užitečné, když je třeba, aby zrušení jedné podřízené úlohy neovlivnilo ostatní.
    • Kořenový CoroutineScope: Pokud výjimka dosáhne kořenového CoroutineScope (například GlobalScope nebo scope vytvořený pomocí CoroutineScope bez Job), je předána globálnímu zpracovateli výjimek CoroutineExceptionHandler. Ve výchozím nastavení, pokud není registrován žádný zpracovatel, je výjimka zaznamenána v System.err.
  • Zachycená výjimka: Pokud je výjimka zachycena pomocí bloku try-catch uvnitř korutiny, je zpracována lokálně a korutina pokračuje v provádění po bloku catch, pokud je to možné. Výjimka se nepřenáší výše.

  • Výjimky související s zrušením (například CancellationException): Tyto výjimky jsou speciální. Používají se pro mechanismus zrušení korutin a obvykle jsou ignorovány většinou zpracovatelů výjimek ve výchozím nastavení. Nevedou k fatálnímu selhání rodičovského Job ve výchozím nastavení.

  • Výjimky v async: Korutina spuštěná pomocí async umisťuje výjimku do svého Deferred. Výjimka je přenášena pouze při volání .await() na tomto Deferred. Do té doby je výjimka "skryta".

import kotlinx.coroutines.*

fun main() = runBlocking {
    val scope = CoroutineScope(SupervisorJob())

    scope.launch {
        try {
            println("Korutina 1 začala")
            delay(100)
            throw RuntimeException("Něco se pokazilo v Korutině 1")
        } catch (e: Exception) {
            println("Zachycena výjimka v Korutině 1: ${e.message}")
        }
    }

    scope.launch {
        println("Korutina 2 začala")
        delay(500)
        println("Korutina 2 dokončena")
    }

    delay(1000) // Čekáme, aby se zobrazil výstup
    scope.cancel() // Zrušíme scope
}

V tomto příkladu je výjimka v Korutině 1 zachycena a Korutina 2 pokračuje v provádění, protože je použit SupervisorJob. Pokud by byl použit místo toho běžný Job, výjimka v Korutině 1 by vedla ke zrušení Korutiny 2.