Was passiert mit einer Coroutine, wenn eine Ausnahme auftritt?
sobes.tech KI
Antwort von AI
Wenn innerhalb einer Coroutine eine Ausnahme auftritt, bestimmt die Abhängigkeit vom Ausnahmetyp (und den Einstellungen des Dispatchers/Kontexts), wie sie behandelt wird.
-
Unbehandelte Ausnahme: Wenn die Ausnahme innerhalb der Coroutine nicht abgefangen wird, wird sie nach oben in der Coroutine-Hierarchie bis zum nächsten
JoboderCoroutineScopepropagiert. Das Verhalten hängt vomJob-Typ ab:Job: Standardmäßig wird bei einer Ausnahme in einer Kind-Coroutine der übergeordneteJobabgebrochen, was zum Abbruch aller anderen Kind-Coroutines führt. Die Ausnahme wird nach oben weitergeleitet.SupervisorJob: Der übergeordneteSupervisorJobwird bei einer Ausnahme in einer Kind-Coroutine nicht abgebrochen. Nur die Coroutine, in der die Ausnahme auftrat, wird abgebrochen. Das ist nützlich, wenn das Abbrechen einer Kind-Aufgabe die anderen nicht beeinflussen soll.CoroutineScope-Wurzel: Wenn die Ausnahme den Wurzel-CoroutineScopeerreicht (z.B.GlobalScopeoder ein mitCoroutineScopeohneJoberstellter Scope), wird sie an den globalenCoroutineExceptionHandlerweitergeleitet. Standardmäßig wird die Ausnahme inSystem.errprotokolliert, wenn kein Handler registriert ist.
-
Abgefangene Ausnahme: Wenn die Ausnahme mit einem
try-catch-Block innerhalb der Coroutine abgefangen wird, wird sie lokal behandelt, und die Coroutine setzt die Ausführung nach demcatch-Block fort, falls möglich. Die Ausnahme wird nicht nach oben weitergeleitet. -
Ausnahmen im Zusammenhang mit Abbruch (z.B.
CancellationException): Diese Ausnahmen sind speziell. Sie werden für den Abbruchmechanismus von Coroutines verwendet und werden von den meisten Standard-Exception-Handlern ignoriert. Sie führen standardmäßig nicht zu einem fatalen Fehler des übergeordnetenJob. -
Ausnahmen bei
async: Eine mitasyncgestartete Coroutine legt die Ausnahme in ihremDeferredab. Die Ausnahme wird nur bei einem Aufruf von.await()auf diesemDeferredweitergeleitet. Bis dahin ist die Ausnahme "versteckt".
import kotlinx.coroutines.*
fun main() = runBlocking {
val scope = CoroutineScope(SupervisorJob())
scope.launch {
try {
println("Coroutine 1 gestartet")
delay(100)
throw RuntimeException("Etwas ist schiefgelaufen in Coroutine 1")
} catch (e: Exception) {
println("Coroutine 1 abgefangene Ausnahme: ${e.message}")
}
}
scope.launch {
println("Coroutine 2 gestartet")
delay(500)
println("Coroutine 2 beendet")
}
delay(1000) // Warten, um die Ausgabe zu sehen
scope.cancel() // Scope abbrechen
}
In diesem Beispiel wird die Ausnahme in Coroutine 1 abgefangen, und Coroutine 2 setzt die Ausführung fort, weil SupervisorJob verwendet wird. Wenn stattdessen ein normaler Job verwendet würde, würde die Ausnahme in Coroutine 1 zum Abbruch von Coroutine 2 führen.