Sobes.tech
Middle

O que você sabe sobre tratamento de erros no Flow?

sobes.tech IA

Resposta da IA

O Flow no Kotlin Coroutines oferece várias formas de lidar com erros:

  1. Operador catch: Intercepta exceções no fluxo ascendente e permite executar uma ação (por exemplo, registar, devolver dados de reserva) ou substituir o fluxo.

    flow {
        emit(1)
        throw RuntimeException("Ocorreu um erro")
    }.catch { e: Throwable ->
        // Tratamento do erro
        emit(-1) // Emitir outro valor em caso de erro
    }.collect { value ->
        // Tratamento de valores
    }
    
  2. Bloco try-catch: Método clássico para tratar exceções em torno de um bloco de código, incluindo a recolha de Flow.

    try {
        flow {
            emit(1)
            throw RuntimeException("Ocorreu um erro")
        }.collect { value ->
            // Tratamento de valores
        }
    } catch (e: Throwable) {
        // Tratamento do erro
    }
    

    Este método captura erros que ocorrem durante a recolha de Flow, mas não erros produzidos pelo emissor de Flow antes da recolha.

  3. Operador onEach com try-catch: Se precisares de tratar erros para cada elemento separadamente.

    flow {
        emit(1)
        emit(2)
        throw RuntimeException("Erro após 2")
        emit(3)
    }.onEach { value ->
        try {
            // Tratamento de cada elemento
            if (value == 2) throw IllegalArgumentException("Valor inválido 2")
        } catch (e: Throwable) {
            // Tratamento do erro para um valor específico
            println("Erro para o valor $value: ${e.message}")
            // Pode lançar exceção para parar o fluxo
            throw e
        }
    }.catch { e: Throwable ->
        // Tratamento de erros não capturados em onEach, ou erros lançados após onEach
        println("Erro final: ${e.message}")
    }.collect { value ->
        println("Valor recolhido: $value")
    }
    
  4. Operador retry / retryWhen: Permitem re-tentar a fonte de Flow em caso de erro.

    • retry: Repetir simplesmente a tentativa um número definido de vezes.
    • retryWhen: Permite definir uma condição para re-tentar.
    var attempt = 0
    flow {
        println("Tentativa ${++attempt}")
        if (attempt < 3) throw RuntimeException("Repetir")
        emit(10)
    }.retryWhen { cause, attempt ->
        // Lógica para determinar se deve re-tentar
        cause is RuntimeException && attempt < 3
    }.collect { value ->
        println("Sucesso: $value")
    }
    
  5. Propagação de exceções: Erros não capturados explicitamente serão propagados para cima na cadeia de Flow e podem ser capturados num bloco try-catch ao redor do coletor de Flow ou com o operador catch.

É importante entender que o operador catch captura erros no fluxo ascendente (upstream). Os erros que ocorrem no fluxo descendente (downstream) após catch não são capturados. Para tratar esses erros, deve-se usar outro catch mais abaixo na cadeia ou um try-catch ao redor do coletor.

Recomendação geral: colocar o tratamento de erros o mais próximo possível da fonte do erro, se possível, mas tendo em conta que catch só trata o fluxo ascendente.