Sobes.tech
Middle

Jakie metody obsługi błędów w korutynach znasz?

sobes.tech AI

Odpowiedź od AI

  • Użycie bloków try...catch. Standardowa metoda obsługi wyjątków. Działa wewnątrz korutyny.

    // Zastosowanie try-catch
    suspend fun fetchData(): String {
        return try {
            // Operacja, która może wyrzucić wyjątek
            throw Exception("Błąd ładowania danych")
            "Dane pomyślnie załadowane"
        } catch (e: Exception) {
            "Błąd: ${e.message}"
        }
    }
    

    try...catch nie jest odpowiedni do obsługi nieprzechwyconych wyjątków wyrzucanych przez korutyny potomne, uruchomione w innym CoroutineScope.

  • CoroutineExceptionHandler. Przechwytuje nieobsłużone wyjątki wyrzucane przez korutyny uruchomione w tym CoroutineScope lub jego CoroutineScope potomne.

    // CoroutineExceptionHandler
    val handler = CoroutineExceptionHandler { _, exception ->
        println("Przechwycono wyjątek: $exception")
    }
    
    // Zastosowanie CoroutineExceptionHandler
    GlobalScope.launch(handler) {
        // Korutyna, która może wyrzucić wyjątek
        throw Exception("Błąd w korutynie")
    }
    

    CoroutineExceptionHandler działa tylko dla nieobsłużonych wyjątków, które nie są obsłużone przez mechanizm zorganizowanej współbieżności.

  • SupervisorJob i supervisorScope. W przeciwieństwie do zwykłego Job, gdy korutyna potomna z błędem powoduje anulowanie Job nadrzędnego, SupervisorJob tego nie robi. supervisorScope tworzy CoroutineScope z SupervisorJob.

    // Użycie supervisorScope
    suspend fun loadMultipleData() = supervisorScope {
        val data1 = async {
            // Może wyrzucić wyjątek
            throw Exception("Błąd w danych 1")
            "Dane 1"
        }
        val data2 = async {
            "Dane 2"
        }
    
        // Obsługa wyjątku dla konkretnej async
        try {
            println("Wynik 1: ${data1.await()}")
        } catch (e: Exception) {
            println("Błąd podczas ładowania danych 1: ${e.message}")
        }
        println("Wynik 2: ${data2.await()}")
    }
    

    Używany dla niezależnych zadań potomnych, gdzie błąd jednego nie powinien wpływać na inne. Nie zastępuje try...catch ani CoroutineExceptionHandler, raczej zmienia zachowanie propagacji wyjątków.

  • Propagacja wyjątków w zorganizowanej współbieżności. Domyślnie, wyjątek w korutynie potomnej powoduje anulowanie korutyny nadrzędnej i wszystkich jej braci.

    // Przykład propagacji wyjątku
    runBlocking {
        val job = launch {
            launch { // Korutyna potomna 1
                delay(100)
                throw Exception("Błąd w potomnej 1")
            }
            launch { // Korutyna potomna 2
                delay(200)
                println("Potomna 2 zakończyła się")
            }
        }
        try {
            job.join()
        } catch (e: Exception) {
            println("Przechwycono wyjątek w nadrzędnym: $e")
        }
    }
    

    To jest domyślne zachowanie zorganizowanej współbieżności, które pomaga unikać wycieków zasobów i stanów.

  • Użycie async z await(). Wyjątki wyrzucane w async nie są automatycznie propagowane. Są przechowywane w Deferred i wyrzucane dopiero przy wywołaniu await().

    // Obsługa wyjątków z async/await
    suspend fun safeAsyncCall() = coroutineScope {
        val deferred = async {
            throw Exception("Błąd w async")
            "Wynik async"
        }
    
        try {
            val result = deferred.await()
            println("Wynik: $result")
        } catch (e: Exception) {
            println("Przechwycono wyjątek z async: ${e.message}")
        }
    }
    

    Pozwala to na selektywną obsługę błędów dla każdego zadania asynchronicznego.

Metoda Cel Obsługuje uncaught? Zmienia propagację?
try...catch Obsługa wyjątków w bieżącej korutynie Nie Nie
CoroutineExceptionHandler Przechwytuje nieobsłużone wyjątki w Scope Tak Nie
SupervisorJob/Scope Zmienia zachowanie propagacji wyjątków Nie Tak
Strukturalna współbieżność Automatyczne anulowanie przy błędzie Tak Tak
async + await() Opóźniona propagacja wyjątków Nie Tak (przed await)