Sobes.tech
Middle

Cosa succede a una coroutine quando si verifica un'eccezione?

sobes.tech AI

Risposta dell'AI

Quando si verifica un'eccezione all'interno di una coroutine, la dipendenza dal tipo di eccezione (e dalle impostazioni del dispatcher/contenuto) determina come verrà gestita.

  • Eccezione non gestita: Se l'eccezione non viene catturata all'interno della coroutine, si propaga verso l'alto nella gerarchia delle coroutines fino al Job o CoroutineScope più vicino. Il comportamento dipende dal tipo di Job:

    • Job: Per impostazione predefinita, quando si verifica un'eccezione in una coroutine figlia, il Job genitore viene cancellato, portando alla cancellazione di tutte le altre sue coroutine figlie. L'eccezione si propaga verso l'alto.
    • SupervisorJob: Il SupervisorJob genitore non viene cancellato quando si verifica un'eccezione in una coroutine figlia. Solo la coroutine in cui si è verificata l'eccezione viene cancellata. Questo è utile quando si desidera che la cancellazione di un task figlio non influenzi gli altri.
    • CoroutineScope radice: Se l'eccezione raggiunge il CoroutineScope radice (ad esempio, GlobalScope o uno creato con CoroutineScope senza Job), viene trasmessa al gestore globale delle eccezioni CoroutineExceptionHandler. Per impostazione predefinita, se non è registrato alcun gestore, l'eccezione viene registrata in System.err.
  • Eccezione catturata: Se l'eccezione viene catturata tramite un blocco try-catch all'interno della coroutine, viene gestita localmente e la coroutine continua l'esecuzione dopo il blocco catch, se possibile. L'eccezione non si propaga verso l'alto.

  • Eccezioni legate alla cancellazione (ad esempio, CancellationException): Queste eccezioni sono particolari. Sono usate per il meccanismo di cancellazione delle coroutines e di solito vengono ignorate dalla maggior parte dei gestori di eccezioni per impostazione predefinita. Non causano un fallimento fatale del Job genitore per impostazione predefinita.

  • Eccezioni in async: La coroutine avviata con async mette l'eccezione nel suo Deferred. L'eccezione viene propagata solo quando si chiama .await() su questo Deferred. Fino a quel momento, l'eccezione è "nascosta".

import kotlinx.coroutines.*

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

    scope.launch {
        try {
            println("Coroutine 1 avviata")
            delay(100)
            throw RuntimeException("Qualcosa è andato storto in Coroutine 1")
        } catch (e: Exception) {
            println("Eccezione catturata in Coroutine 1: ${e.message}")
        }
    }

    scope.launch {
        println("Coroutine 2 avviata")
        delay(500)
        println("Coroutine 2 terminata")
    }

    delay(1000) // Attendi per vedere l'output
    scope.cancel() // Annulla lo scope
}

In questo esempio, l'eccezione in Coroutine 1 viene catturata e Coroutine 2 continua l'esecuzione perché si utilizza SupervisorJob. Se si usasse invece un Job normale, l'eccezione in Coroutine 1 porterebbe all'annullamento di Coroutine 2.