Sobes.tech
Middle

¿Qué formas de manejo de errores en corutinas conoces?

sobes.tech AI

Respuesta de la IA

  • Uso de bloques try...catch. Método estándar para manejar excepciones. Funciona dentro de una coroutine.

    // Uso de try-catch
    suspend fun fetchData(): String {
        return try {
            // Operación que puede lanzar una excepción
            throw Exception("Error al cargar datos")
            "Datos cargados con éxito"
        } catch (e: Exception) {
            "Error: ${e.message}"
        }
    }
    

    try...catch no es adecuado para manejar excepciones no capturadas lanzadas desde coroutines hijas, ejecutadas en otro CoroutineScope.

  • CoroutineExceptionHandler. Captura excepciones no manejadas lanzadas por coroutines que se ejecutan en este CoroutineScope o en sus CoroutineScope hijos.

    // CoroutineExceptionHandler
    val handler = CoroutineExceptionHandler { _, exception ->
        println("Excepción capturada: $exception")
    }
    
    // Uso de CoroutineExceptionHandler
    GlobalScope.launch(handler) {
        // Coroutine que puede lanzar una excepción
        throw Exception("Error en la coroutine")
    }
    

    CoroutineExceptionHandler solo se activa para excepciones no manejadas por el mecanismo de concurrencia estructurada.

  • SupervisorJob y supervisorScope. A diferencia de un Job normal, cuando una coroutine hija con error causa la cancelación del Job padre, SupervisorJob no cancela el Job padre ante un error en una coroutine hija. supervisorScope crea un CoroutineScope con un SupervisorJob.

    // Uso de supervisorScope
    suspend fun loadMultipleData() = supervisorScope {
        val data1 = async {
            // Puede lanzar una excepción
            throw Exception("Error en datos 1")
            "Datos 1"
        }
        val data2 = async {
            "Datos 2"
        }
    
        // Se puede manejar la excepción de una async específica
        try {
            println("Resultado 1: ${data1.await()}")
        } catch (e: Exception) {
            println("Error al cargar datos 1: ${e.message}")
        }
        println("Resultado 2: ${data2.await()}")
    }
    

    Se usa para tareas hijas independientes, donde el error de una no debe afectar a las otras. No reemplaza a try...catch o CoroutineExceptionHandler, sino que cambia el comportamiento en la propagación de excepciones.

  • Propagación de excepciones en concurrencia estructurada. Por defecto, una excepción en una coroutine hija cancela la coroutine padre y a todos sus hermanos.

    // Ejemplo de propagación de excepción
    runBlocking {
        val job = launch {
            launch { // Coroutine hija 1
                delay(100)
                throw Exception("Error en la hija 1")
            }
            launch { // Coroutine hija 2
                delay(200)
                println("Hija 2 completada")
            }
        }
        try {
            job.join()
        } catch (e: Exception) {
            println("Excepción capturada en la padre: $e")
        }
    }
    

    Este comportamiento básico de la concurrencia estructurada ayuda a evitar fugas de recursos y estados.

  • Uso de async con await(). Las excepciones lanzadas en async no se propagan automáticamente. Se almacenan en Deferred y se lanzan solo al llamar a await().

    // Manejo de excepciones con async/await
    suspend fun safeAsyncCall() = coroutineScope {
        val deferred = async {
            throw Exception("Error en async")
            "Resultado de async"
        }
    
        try {
            val result = deferred.await()
            println("Resultado: $result")
        } catch (e: Exception) {
            println("Excepción capturada desde async: ${e.message}")
        }
    }
    

    Esto permite manejar errores de forma selectiva en cada tarea asíncrona.

Método Propósito ¿Maneja uncaught? ¿Cambia la propagación?
try...catch Manejo de excepciones en la coroutine actual No No
CoroutineExceptionHandler Captura excepciones no manejadas en Scope No
SupervisorJob/Scope Cambia comportamiento en la propagación de excepciones No
Concurrencia estructurada Cancelación automática en error
async + await() Propagación diferida de excepciones No Sí (antes de await)