Sobes.tech
Middle

Que métodos de tratamento de erros em corrotinas você conhece?

sobes.tech IA

Resposta da IA

  • Uso de blocos try...catch. Método padrão para lidar com exceções. Funciona dentro de uma coroutine.

    // Uso de try-catch
    suspend fun fetchData(): String {
        return try {
            // Operação que pode lançar uma exceção
            throw Exception("Erro ao carregar dados")
            "Dados carregados com sucesso"
        } catch (e: Exception) {
            "Erro: ${e.message}"
        }
    }
    

    try...catch não é adequado para lidar com exceções não capturadas lançadas por coroutines filhas, executadas em outro CoroutineScope.

  • CoroutineExceptionHandler. Intercepta exceções não tratadas lançadas por coroutines que são executadas neste CoroutineScope ou em seus CoroutineScope filhos.

    // CoroutineExceptionHandler
    val handler = CoroutineExceptionHandler { _, exception ->
        println("Exceção capturada: $exception")
    }
    
    // Uso de CoroutineExceptionHandler
    GlobalScope.launch(handler) {
        // Coroutine que pode lançar uma exceção
        throw Exception("Erro na coroutine")
    }
    

    CoroutineExceptionHandler só é acionado para exceções não tratadas pelo mecanismo de concorrência estruturada.

  • SupervisorJob e supervisorScope. Diferentemente de um Job normal, quando uma coroutine filha com erro causa a cancelamento do Job pai, SupervisorJob não cancela o Job pai devido a um erro na coroutine filha. supervisorScope cria um CoroutineScope com um SupervisorJob.

    // Uso de supervisorScope
    suspend fun loadMultipleData() = supervisorScope {
        val data1 = async {
            // Pode lançar uma exceção
            throw Exception("Erro em dados 1")
            "Dados 1"
        }
        val data2 = async {
            "Dados 2"
        }
    
        // Pode tratar a exceção de uma async específica
        try {
            println("Resultado 1: ${data1.await()}")
        } catch (e: Exception) {
            println("Erro ao carregar dados 1: ${e.message}")
        }
        println("Resultado 2: ${data2.await()}")
    }
    

    Usado para tarefas filhas independentes, onde o erro de uma não deve afetar as outras. Não substitui try...catch ou CoroutineExceptionHandler, mas altera o comportamento de propagação de exceções.

  • Propagação de exceções na concorrência estruturada. Por padrão, uma exceção na coroutine filha cancela a coroutine pai e todos os seus irmãos.

    // Exemplo de propagação de exceção
    runBlocking {
        val job = launch {
            launch { // Coroutine filha 1
                delay(100)
                throw Exception("Erro na filha 1")
            }
            launch { // Coroutine filha 2
                delay(200)
                println("Filha 2 terminou")
            }
        }
        try {
            job.join()
        } catch (e: Exception) {
            println("Exceção capturada no pai: $e")
        }
    }
    

    Este é o comportamento padrão da concorrência estruturada, que ajuda a evitar vazamentos de recursos e estados.

  • Uso de async com await(). As exceções lançadas em async não se propagam automaticamente. Elas ficam armazenadas em Deferred e são lançadas apenas ao chamar await().

    // Tratamento de exceções com async/await
    suspend fun safeAsyncCall() = coroutineScope {
        val deferred = async {
            throw Exception("Erro em async")
            "Resultado de async"
        }
    
        try {
            val result = deferred.await()
            println("Resultado: $result")
        } catch (e: Exception) {
            println("Exceção capturada de async: ${e.message}")
        }
    }
    

    Isso permite tratar erros de forma seletiva para cada tarefa assíncrona.

Método Propósito Trata uncaught? Altera propagação?
try...catch Tratamento de exceções na coroutine atual Não Não
CoroutineExceptionHandler Captura exceções não tratadas no Scope Sim Não
SupervisorJob/Scope Altera o comportamento de propagação de exceções Não Sim
Concurrency estruturada Cancelamento automático em erro Sim Sim
async + await() Propagação adiada de exceções Não Sim (antes do await)