0Pricing
Kotlin Academy · Lekcja

CoroutineExceptionHandler: globalny handler nieprzechwyconych wyjątków

Zainstaluj CoroutineExceptionHandler, aby rejestrować nieobsłużone wyjątki lub odzyskiwać po nich działanie.

CoroutineExceptionHandler: globalny handler nieprzechwyconych wyjątków to bezpłatna lekcja Kotlin Academy na CoddyKit. To lekcja 2 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Kotlin Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Kotlin Academy zawiera 4 lekcji w sumie.

Czym jest CoroutineExceptionHandler?

CoroutineExceptionHandler to element kontekstu obsługujący nieprzechwycone wyjątki z korutyn, które nie mają obsługi catch. Działa jako mechanizm ostateczny.

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)
}

Tylko dla korutyn głównych

CoroutineExceptionHandler przechwytuje wyjątki tylko z korutyn głównych (uruchomionych bezpośrednio w zakresie). Korutyny potomne propagują wyjątki do korutyny nadrzędnej, a nie do handlera.

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() } }
}

Nie tłumi wyjątku

Handler jest wywoływany po tym, jak wyjątek anulował już korutynę. Służy do rejestrowania, raportowania awarii lub sprzątania — nie do wznawiania wykonywania.

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

Połączenie SupervisorJob + CoroutineExceptionHandler jest standardowym wzorcem dla długotrwałych zakresów: dzieci kończą się niepowodzeniem niezależnie od siebie, a nieobsłużone błędy są rejestrowane.

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 z async

W przypadku async wyjątki są przechowywane w obiekcie Deferred i zgłaszane przy wywołaniu await(). Handler NIE jest uruchamiany dla async, chyba że nie oczekuje się na obiekt deferred.

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()
}

Porównanie z Thread.UncaughtExceptionHandler

W przeciwieństwie do mechanizmu UncaughtExceptionHandler w Javie handler Kotlina jest częścią kontekstu korutyny i ma zastosowanie tylko do korutyn działających w tym zakresie.

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") }

Wzorzec rejestrowania z MDC

W aplikacjach serwerowych handler może przechwytywać informacje z kontekstu korutyny, takie jak identyfikatory żądań, na potrzeby strukturalnego rejestrowania przed przekazaniem ich do frameworka rejestrowania.

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)
}

Integracja z raportowaniem awarii

Należy używać handlera do przekazywania nieprzechwyconych wyjątków do usług raportowania awarii, takich jak Firebase Crashlytics lub 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()
}

Dziedziczenie handlera

Handler z kontekstu nadrzędnego NIE jest automatycznie dziedziczony przez korutyny potomne. Aby został uruchomiony, musi znajdować się w kontekście korutyny głównej.

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)
}

Podsumowanie dobrych praktyk

Należy zawsze instalować CoroutineExceptionHandler w zakresach na poziomie aplikacji lub funkcji. Należy rejestrować każdy wyjątek niezwiązany z anulowaniem. Nigdy nie należy polegać na nim w sterowaniu przepływem — służy wyłącznie do obserwowalności.

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()
}

Szybkie sprawdzenie

Dla jakiego typu korutyny CoroutineExceptionHandler NIE jest uruchamiany automatycznie?

Podsumowanie

CoroutineExceptionHandler jest mechanizmem ostatecznym do obserwowania nieprzechwyconych wyjątków w korutynach głównych. Należy łączyć go z SupervisorJob w długotrwałych zakresach. Należy używać go do rejestrowania i raportowania awarii — nigdy do sterowania przepływem.

Często zadawane pytania

Czy lekcja „CoroutineExceptionHandler: globalny handler nieprzechwyconych wyjątków” jest bezpłatna?

Tak — pełny tekst „CoroutineExceptionHandler: globalny handler nieprzechwyconych wyjątków” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Kotlin Academy, przejdź na CoddyKit PRO. Kurs Kotlin Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „CoroutineExceptionHandler: globalny handler nieprzechwyconych wyjątków”?

Zainstaluj CoroutineExceptionHandler, aby rejestrować nieobsłużone wyjątki lub odzyskiwać po nich działanie. Ćwiczysz Kotlin Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć Kotlin Academy?

Nie wymagamy żadnego doświadczenia. Kotlin Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 2 z 4.

Ile czasu zajmuje lekcja „CoroutineExceptionHandler: globalny handler nieprzechwyconych wyjątków”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji Kotlin Academy?

Tak. Każda lekcja Kotlin Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. SupervisorJob a Job: izolowanie błędów
  2. CoroutineExceptionHandler: globalny handler nieprzechwyconych wyjątków
  3. Propagacja wyjątków w async/await
  4. Projektowanie odpornych architektur korutyn
← Powrót do Kotlin Academy