CoroutineExceptionHandler: gestore globale delle eccezioni non catturate
Installi un CoroutineExceptionHandler per registrare o recuperare le eccezioni non gestite.
CoroutineExceptionHandler: gestore globale delle eccezioni non catturate è una lezione Kotlin Academy gratuita su CoddyKit. Questa è la lezione 2 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Kotlin Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Kotlin Academy include 4 lezioni in totale.
Che cos'è CoroutineExceptionHandler?
CoroutineExceptionHandler è un elemento del contesto che gestisce le eccezioni non catturate dalle coroutine che non dispongono di un gestore catch. Funge da ultima risorsa.
import kotlinx.coroutines.*
val handler = CoroutineExceptionHandler { context, exception ->
println("Caught unhandled: ${exception.message}")
}
fun main() = runBlocking {
val scope = CoroutineScope(Dispatchers.Default + handler)
scope.launch { throw RuntimeException("oops") }
delay(100)
}Solo per le coroutine radice
CoroutineExceptionHandler cattura le eccezioni solo dalle coroutine radice (avviate direttamente su uno scope). Le coroutine figlie propagano le eccezioni al padre, non al gestore.
import kotlinx.coroutines.*
val handler = CoroutineExceptionHandler { _, e -> println("Handler: ${e.message}") }
fun main() = runBlocking {
// Root coroutine — handler fires:
CoroutineScope(handler).launch {
throw RuntimeException("root error")
}
delay(100)
// NOT handler (child of coroutineScope):
// launch { launch { throw RuntimeException() } }
}Non sopprime l'eccezione
Il gestore viene invocato dopo che l'eccezione ha già annullato la coroutine. Serve per la registrazione, la segnalazione degli arresti anomali o la pulizia, non per riprendere l'esecuzione.
import kotlinx.coroutines.*
val handler = CoroutineExceptionHandler { _, e ->
println("[CrashReport] ${e::class.simpleName}: ${e.message}")
// send to Crashlytics, Sentry, etc.
}
fun main() = runBlocking {
CoroutineScope(SupervisorJob() + handler).apply {
launch { throw IllegalStateException("state error") }
launch { delay(100); println("still alive") }
delay(200)
cancel()
}
}Handler + SupervisorJob
La combinazione di SupervisorJob + CoroutineExceptionHandler è il modello standard per gli scope di lunga durata: i figli falliscono indipendentemente e gli errori non gestiti vengono registrati.
import kotlinx.coroutines.*
class AppScope {
private val handler = CoroutineExceptionHandler { _, e ->
println("Uncaught: ${e.message}")
}
val scope = CoroutineScope(SupervisorJob() + Dispatchers.Default + handler)
}
fun main() = runBlocking {
val app = AppScope()
app.scope.launch { throw RuntimeException("task failed") }
app.scope.launch { delay(100); println("other task ok") }
delay(200)
app.scope.cancel()
}Handler con async
Con async, le eccezioni vengono memorizzate in Deferred e lanciate in corrispondenza di await(). Il gestore NON viene attivato per async, a meno che il deferred non venga atteso.
import kotlinx.coroutines.*
val handler = CoroutineExceptionHandler { _, e -> println("Handler: ${e.message}") }
fun main() = runBlocking {
val scope = CoroutineScope(SupervisorJob() + handler)
val deferred = scope.async { throw RuntimeException("async error") }
try {
deferred.await() // exception thrown here
} catch (e: RuntimeException) {
println("Caught from await: ${e.message}")
}
delay(50)
scope.cancel()
}Confronto con Thread.UncaughtExceptionHandler
A differenza di UncaughtExceptionHandler di Java, il gestore di Kotlin fa parte del contesto della coroutine e si applica solo alle coroutine presenti nello scope in questione.
import kotlinx.coroutines.*
// Java style (applies to threads):
Thread.setDefaultUncaughtExceptionHandler { t, e ->
println("Thread ${t.name} threw: ${e.message}")
}
// Kotlin coroutine style (applies to coroutines in scope):
val handler = CoroutineExceptionHandler { _, e ->
println("Coroutine threw: ${e.message}")
}
fun main() = runBlocking { println("Handlers target different concurrency models") }Modello di registrazione con MDC
Nelle applicazioni server, il gestore può acquisire le informazioni del contesto della coroutine (come gli ID delle richieste) per la registrazione strutturata prima di inoltrarle al framework di logging.
import kotlinx.coroutines.*
val handler = CoroutineExceptionHandler { ctx, e ->
val jobName = ctx[CoroutineName]?.name ?: "unknown"
println("[${jobName}] ERROR: ${e.message}")
}
fun main() = runBlocking {
CoroutineScope(SupervisorJob() + handler).launch(CoroutineName("DataLoader")) {
throw RuntimeException("fetch failed")
}
delay(100)
}Integrazione con la segnalazione degli arresti anomali
Utilizzi il gestore per inoltrare le eccezioni non catturate a servizi di segnalazione degli arresti anomali come Firebase Crashlytics o Sentry.
import kotlinx.coroutines.*
object CrashReporter {
fun record(e: Throwable) = println("[Crashlytics] ${e.message}")
}
val handler = CoroutineExceptionHandler { _, e ->
if (e !is CancellationException) CrashReporter.record(e)
}
val appScope = CoroutineScope(SupervisorJob() + Dispatchers.Default + handler)
fun main() = runBlocking {
appScope.launch { throw RuntimeException("unhandled in production") }
delay(100)
appScope.cancel()
}Ereditarietà del gestore
Il gestore del contesto padre NON viene ereditato automaticamente dalle coroutine figlie. Deve trovarsi nel contesto della coroutine radice per poter essere attivato.
import kotlinx.coroutines.*
val handler = CoroutineExceptionHandler { _, e -> println("Handler: ${e.message}") }
fun main() = runBlocking {
// Handler only fires at root level:
CoroutineScope(SupervisorJob() + handler).launch {
// Child of root — exception propagates to root handler:
launch { throw RuntimeException("nested") }
}
delay(100)
}Riepilogo delle buone pratiche
Installi sempre un CoroutineExceptionHandler negli scope a livello di applicazione o di funzionalità. Registri ogni eccezione che non sia dovuta all'annullamento. Non si affidi mai a questo gestore per il flusso di controllo: serve solo per l'osservabilità.
import kotlinx.coroutines.*
val globalHandler = CoroutineExceptionHandler { ctx, e ->
if (e !is CancellationException) {
println("[ERROR] ${ctx[CoroutineName]?.name}: ${e.message}")
}
}
val appScope = CoroutineScope(SupervisorJob() + Dispatchers.Default + globalHandler)
fun main() = runBlocking {
appScope.launch(CoroutineName("Auth")) { throw RuntimeException("token expired") }
delay(100); appScope.cancel()
}Verifica rapida
Per quale tipo di coroutine CoroutineExceptionHandler NON viene attivato automaticamente?
Riepilogo
CoroutineExceptionHandler è un osservatore di ultima risorsa per le eccezioni non catturate nelle coroutine radice. Lo combini con SupervisorJob per gli scope di lunga durata. Lo utilizzi per la registrazione e la segnalazione degli arresti anomali, mai per il flusso di controllo.
Domande Frequenti
La lezione «CoroutineExceptionHandler: gestore globale delle eccezioni non catturate» è gratuita?
Sì — il testo completo di «CoroutineExceptionHandler: gestore globale delle eccezioni non catturate» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Kotlin Academy, passa a CoddyKit PRO. Il corso Kotlin Academy include 4 lezioni in totale.
Cosa imparerò in «CoroutineExceptionHandler: gestore globale delle eccezioni non catturate»?
Installi un CoroutineExceptionHandler per registrare o recuperare le eccezioni non gestite. Eserciti Kotlin Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare Kotlin Academy?
Non è richiesta alcuna esperienza precedente. Kotlin Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 2 di 4.
Quanto tempo richiede la lezione «CoroutineExceptionHandler: gestore globale delle eccezioni non catturate»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione Kotlin Academy?
Sì. Ogni lezione Kotlin Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- SupervisorJob e Job: isolamento degli errori
- CoroutineExceptionHandler: gestore globale delle eccezioni non catturate
- Propagazione delle eccezioni con async/await
- Progettare architetture resilienti per le coroutine