Ce se întâmplă cu o corutină atunci când apare o excepție?
sobes.tech AI
Răspuns de la AI
Când apare o excepție în interiorul unei coroutine, dependența de tipul excepției (și setările dispatcher/conținut) determină modul în care aceasta va fi gestionată.
-
Excepție necontrolată: Dacă excepția nu este capturată în interiorul coroutinei, aceasta se propagă în sus în ierarhia coroutinelor până la cel mai apropiat
JobsauCoroutineScope. Comportamentul depinde de tipul deJob:Job: În mod implicit, atunci când apare o excepție într-o coroutine fiică,Job-ul părinte este anulat, ceea ce duce la anularea tuturor celorlalte coroutines sale fiice. Excepția se propagă în sus.SupervisorJob:SupervisorJobpărinte nu este anulat atunci când apare o excepție într-o coroutine fiică. Doar coroutinea în care a avut loc excepția este anulată. Acest lucru este util atunci când vrei ca anularea unei sarcini fiice să nu afecteze celelalte.CoroutineScoperădăcină: Dacă excepția ajunge laCoroutineScoperădăcină (de exemplu,GlobalScopesau un scope creat cuCoroutineScopefărăJob), ea este transmisă handler-ului global de excepțiiCoroutineExceptionHandler. În mod implicit, dacă nu există un handler înregistrat, excepția este înregistrată înSystem.err.
-
Excepție capturată: Dacă excepția este capturată cu ajutorul unui bloc
try-catchîn interiorul coroutinei, ea este gestionată local și coroutine continuă execuția după bloculcatch, dacă este posibil. Excepția nu se propagă în sus. -
Excepții legate de anulare (de exemplu,
CancellationException): Aceste excepții sunt speciale. Ele sunt folosite pentru mecanismul de anulare a coroutinelor și sunt de obicei ignorate de majoritatea handler-ilor de excepții implicit. Ele nu duc la o eroare fatală aJob-ului părinte implicit. -
Excepții în
async: Coroutinele lansate cuasyncplasează excepția înDeferred-ul său. Excepția este propagată doar atunci când se apelează.await()pe acestDeferred. Până atunci, excepția este "ascunsă".
import kotlinx.coroutines.*
fun main() = runBlocking {
val scope = CoroutineScope(SupervisorJob())
scope.launch {
try {
println("Coroutine 1 început")
delay(100)
throw RuntimeException("Ceva nu a mers bine în Coroutine 1")
} catch (e: Exception) {
println("Excepție capturată în Coroutine 1: ${e.message}")
}
}
scope.launch {
println("Coroutine 2 început")
delay(500)
println("Coroutine 2 terminat")
}
delay(1000) // Așteptăm pentru a vedea output-ul
scope.cancel() // Anulăm scope-ul
}
În acest exemplu, excepția din Coroutine 1 este capturată, iar Coroutine 2 continuă execuția deoarece se folosește SupervisorJob. Dacă s-ar folosi în loc un Job obișnuit, excepția din Coroutine 1 ar duce la anularea Coroutine 2.