Sobes.tech
Middle

Co wiesz o obsłudze błędów w Flow?

sobes.tech AI

Odpowiedź od AI

Flow w Kotlin Coroutines oferuje kilka sposobów obsługi błędów:

  1. Operator catch: Przechwytuje wyjątki w strumieniu wznoszącym i pozwala wykonać akcję (np. logowanie, zwrócenie danych zapasowych) lub zastąpić strumień.

    flow {
        emit(1)
        throw RuntimeException("Wystąpił błąd")
    }.catch { e: Throwable ->
        // Obsługa błędu
        emit(-1) // Emituj inną wartość w przypadku błędu
    }.collect { value ->
        // Obsługa wartości
    }
    
  2. Blok try-catch: Klasyczny sposób obsługi wyjątków wokół fragmentu kodu, w tym zbierania Flow.

    try {
        flow {
            emit(1)
            throw RuntimeException("Wystąpił błąd")
        }.collect { value ->
            // Obsługa wartości
        }
    } catch (e: Throwable) {
        // Obsługa błędu
    }
    

    Ten sposób przechwytuje błędy występujące podczas zbierania Flow, ale nie błędy generowane przez emitera Flow przed zbieraniem.

  3. Operator onEach z try-catch: Jeśli chcesz obsłużyć błędy dla każdego elementu osobno.

    flow {
        emit(1)
        emit(2)
        throw RuntimeException("Błąd po 2")
        emit(3)
    }.onEach { value ->
        try {
            // Obsługa każdego elementu
            if (value == 2) throw IllegalArgumentException("Nieprawidłowa wartość 2")
        } catch (e: Throwable) {
            // Obsługa błędu dla konkretnej wartości
            println("Błąd dla wartości $value: ${e.message}")
            // Można rzucić wyjątek dalej, aby zatrzymać strumień
            throw e
        }
    }.catch { e: Throwable ->
        // Obsługa błędów nieprzechwyconych w onEach lub błędów rzuconych po onEach
        println("Ostateczny błąd: ${e.message}")
    }.collect { value ->
        println("Zebrana wartość: $value")
    }
    
  4. Operator retry / retryWhen: Pozwalają powtórzyć próbę źródła Flow w przypadku błędu.

    • retry: Po prostu powtarza próbę określoną liczbę razy.
    • retryWhen: Pozwala zdefiniować warunek powtórzenia.
    var attempt = 0
    flow {
        println("Próba ${++attempt}")
        if (attempt < 3) throw RuntimeException("Powtórka")
        emit(10)
    }.retryWhen { cause, attempt ->
        // Logika określenia, czy powtórzyć
        cause is RuntimeException && attempt < 3
    }.collect { value ->
        println("Sukces: $value")
    }
    
  5. Propagacja wyjątków: Błędy nieprzechwycone jawnie będą propagowane w górę łańcucha Flow i mogą być przechwycone w bloku try-catch wokół zbieracza Flow lub operatorem catch.

Ważne jest, aby zrozumieć, że operator catch przechwytuje błędy w strumieniu wznoszącym (upstream). Błędy pojawiające się w strumieniu opadającym (downstream) po catch nie są przechwytywane. Aby obsłużyć takie błędy, należy użyć innego catch poniżej w łańcuchu lub try-catch wokół zbieracza.

Ogólna rekomendacja: umieścić obsługę błędów tak blisko źródła błędu, jak to możliwe, ale pamiętać, że catch obsługuje tylko strumień wznoszący.