Sobes.tech
Middle

Quali metodi di gestione degli errori nelle coroutine conosci?

sobes.tech AI

Risposta dell'AI

  • Uso di blocchi try...catch. Metodo standard per la gestione delle eccezioni. Funziona all'interno di una coroutine.

    // Applicazione di try-catch
    suspend fun fetchData(): String {
        return try {
            // Operazione che può generare un'eccezione
            throw Exception("Errore nel caricamento dei dati")
            "Dati caricati con successo"
        } catch (e: Exception) {
            "Errore: ${e.message}"
        }
    }
    

    try...catch non è adatto per gestire eccezioni non catturate lanciate da coroutine figlie, eseguite in un altro CoroutineScope.

  • CoroutineExceptionHandler. Intercetta le eccezioni non gestite lanciate da coroutine avviate in questo CoroutineScope o nei suoi CoroutineScope figli.

    // CoroutineExceptionHandler
    val handler = CoroutineExceptionHandler { _, exception ->
        println("Eccezione intercettata: $exception")
    }
    
    // Applicazione di CoroutineExceptionHandler
    GlobalScope.launch(handler) {
        // Coroutine che può generare un'eccezione
        throw Exception("Errore nella coroutine")
    }
    

    CoroutineExceptionHandler si attiva solo per eccezioni non gestite dal meccanismo di concorrenza strutturata.

  • SupervisorJob e supervisorScope. A differenza di un Job normale, quando una coroutine figlia con errore causa l'annullamento del Job genitore, SupervisorJob non annulla il Job genitore in caso di errore della coroutine figlia. supervisorScope crea uno CoroutineScope con un SupervisorJob.

    // Uso di supervisorScope
    suspend fun loadMultipleData() = supervisorScope {
        val data1 = async {
            // Può generare un'eccezione
            throw Exception("Errore nei dati 1")
            "Dati 1"
        }
        val data2 = async {
            "Dati 2"
        }
    
        // Gestione dell'eccezione per un async specifico
        try {
            println("Risultato 1: ${data1.await()}")
        } catch (e: Exception) {
            println("Errore nel caricamento dei dati 1: ${e.message}")
        }
        println("Risultato 2: ${data2.await()}")
    }
    

    Usato per compiti figli indipendenti, dove l'errore di uno non deve influenzare gli altri. Non sostituisce try...catch o CoroutineExceptionHandler, ma modifica il comportamento di propagazione delle eccezioni.

  • Propagazione delle eccezioni nella concorrenza strutturata. Per impostazione predefinita, un'eccezione in una coroutine figlia cancella la coroutine genitore e tutti i suoi fratelli.

    // Esempio di propagazione dell'eccezione
    runBlocking {
        val job = launch {
            launch { // Coroutine figlia 1
                delay(100)
                throw Exception("Errore in figlia 1")
            }
            launch { // Coroutine figlia 2
                delay(200)
                println("Figlia 2 completata")
            }
        }
        try {
            job.join()
        } catch (e: Exception) {
            println("Eccezione catturata nel genitore: $e")
        }
    }
    

    Questo è il comportamento di default della concorrenza strutturata, che aiuta a evitare perdite di risorse e stati.

  • Uso di async con await(). Le eccezioni lanciate in async non si propagano automaticamente. Sono memorizzate in Deferred e vengono lanciate solo al momento di chiamare await().

    // Gestione delle eccezioni con async/await
    suspend fun safeAsyncCall() = coroutineScope {
        val deferred = async {
            throw Exception("Errore in async")
            "Risultato di async"
        }
    
        try {
            val result = deferred.await()
            println("Risultato: $result")
        } catch (e: Exception) {
            println("Eccezione catturata da async: ${e.message}")
        }
    }
    

    Questo permette di gestire gli errori in modo selettivo per ogni task asincrono.

Metodo Scopo Gestisce uncaught? Cambia propagazione?
try...catch Gestione delle eccezioni nella coroutine corrente No No
CoroutineExceptionHandler Cattura eccezioni non gestite nello Scope No
SupervisorJob/Scope Modifica il comportamento di propagazione delle eccezioni No
Concorrenza strutturata Annullamento automatico in caso di errore
async + await() Propagazione ritardata delle eccezioni No Sì (prima di await)