Kotlin Academy · Lección

catch y onCompletion: gestión de errores en Flow

Capture excepciones ascendentes y reaccione a los eventos de finalización del flujo.

Lección 2 de 413 pasos

catch y onCompletion: gestión de errores en Flow es una lección gratuita de Kotlin Academy en CoddyKit. Esta es la lección 2 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Kotlin Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Kotlin Academy incluye 4 lecciones en total.

Conceptos básicos de las excepciones en Flow

Las excepciones en un flujo lo terminan. Sin un gestor, la excepción se propaga al recopilador y el flujo finaliza.

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
    try {
        flow {
            emit(1)
            throw RuntimeException("stream error")
            emit(2)
        }.collect { println(it) }
    } catch (e: Exception) {
        println("Caught: ${e.message}")
    }
}

Operador catch

catch gestiona las excepciones del flujo ascendente y puede emitir valores alternativos o volver a lanzar la excepción. No captura las excepciones lanzadas por el propio recopilador.

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
    flow {
        emit(1)
        throw RuntimeException("oops")
    }.catch { e ->
        println("Caught: ${e.message}")
        emit(-1)  // fallback value
    }.collect { println(it) } // 1, then -1
}

catch solo gestiona el flujo ascendente

catch solo intercepta las excepciones del constructor del flujo y de los operadores ascendentes, no las de la lambda de collect.

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
    try {
        flowOf(1, 2, 3)
            .catch { e -> println("upstream: ${e.message}") }
            .collect {
                if (it == 2) throw RuntimeException("collector error") // not caught by catch
                println(it)
            }
    } catch (e: Exception) {
        println("Collector exception: ${e.message}")
    }
}

Volver a lanzar una excepción en catch

Puede inspeccionar la excepción y volver a lanzar selectivamente aquellas que no pueda gestionar.

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
    try {
        flow {
            emit(1)
            throw IllegalStateException("state error")
        }.catch { e ->
            if (e is RuntimeException) { emit(-1); return@catch }
            throw e  // rethrow unknown exceptions
        }.collect { println(it) }
    } catch (e: Exception) {
        println("Rethrown: ${e.message}")
    }
}

Operador onCompletion

onCompletion se ejecuta cuando el flujo se completa, normalmente o con una excepción. Su parámetro cause no es null cuando se produce un error.

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
    flowOf(1, 2, 3)
        .onCompletion { cause ->
            if (cause == null) println("Completed normally")
            else println("Failed: ${cause.message}")
        }
        .collect { println(it) }
}

onCompletion en caso de error

onCompletion se ejecuta incluso cuando se produce una excepción en el flujo ascendente. Recibe la excepción como cause, pero no la suprime: la excepción sigue propagándose.

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
    try {
        flow {
            emit(1)
            throw RuntimeException("error")
        }.onCompletion { cause ->
            println("onCompletion cause=${cause?.message}")
        }.collect { println(it) }
    } catch (e: Exception) {
        println("outer catch: ${e.message}")
    }
}

Combinación de catch y onCompletion

Use catch para recuperarse y emitir valores alternativos, y después onCompletion para registrar información o liberar recursos independientemente del resultado.

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
    flow {
        emit("ok")
        throw RuntimeException("network error")
    }.catch { e ->
        emit("fallback") // recover
    }.onCompletion {
        println("Stream done — release resources")
    }.collect { println(it) }
}

Operador retry

retry(n) { ... } vuelve a suscribirse al flujo ascendente cuando se produce una excepción, hasta n veces.

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
var attempt = 0
fun unstableFlow() = flow {
    attempt++
    if (attempt < 3) throw RuntimeException("attempt $attempt failed")
    emit("success on attempt $attempt")
}
fun main() = runBlocking {
    unstableFlow()
        .retry(3) { e -> println("retrying: ${e.message}"); true }
        .collect { println(it) }
}

retryWhen para lógica personalizada

retryWhen proporciona la excepción y el número de intento para que pueda añadir una espera progresiva o filtrar qué excepciones activan un reintento.

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
    var n = 0
    flow {
        if (n++ < 2) throw IOException("IO error")
        emit("done")
    }.retryWhen { cause, attempt ->
        cause is IOException && attempt < 3
    }.collect { println(it) }
}

Operador onStart

onStart se ejecuta antes de la primera emisión; resulta útil para mostrar estados de carga o inicializar recursos antes de que lleguen los datos.

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
    flowOf("data")
        .onStart { emit("Loading...") }
        .onCompletion { emit("Done") }
        .collect { println(it) }
}

Manejo de errores en llamadas reales a API

Envuelva los flujos del repositorio con catch para asignar las excepciones a errores de dominio y con onCompletion para ocultar los indicadores de carga.

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
sealed class State { object Loading : State(); data class Data(val v: String) : State(); data class Error(val msg: String) : State() }
fun apiFlow(): Flow<String> = flow { delay(50); emit("response") }
fun uiFlow(): Flow<State> = apiFlow()
    .map { State.Data(it) as State }
    .onStart { emit(State.Loading) }
    .catch { e -> emit(State.Error(e.message ?: "unknown")) }
fun main() = runBlocking { uiFlow().collect { println(it) } }

Comprobación rápida

¿Cuál es la principal limitación del operador catch?

Resumen

catch gestiona las excepciones del flujo ascendente y puede emitir valores alternativos. onCompletion se ejecuta siempre (en condiciones normales o de error) para realizar tareas de limpieza o registro. Combínelos con retry/retryWhen para crear canalizaciones de flujo resistentes.

Gratis para empezar

Aprende Kotlin con un tutor de IA — gratis

Escribe y ejecuta código real en tu navegador, obtén ayuda instantánea de un tutor de IA disponible 24/7 y continúa donde lo dejaste en la web o en la aplicación.

Cursos
51
Lecciones
203

Preguntas frecuentes

¿La lección «catch y onCompletion: gestión de errores en Flow» es gratis?

Sí — el texto completo de «catch y onCompletion: gestión de errores en Flow» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Kotlin Academy, actualiza a CoddyKit PRO. El curso de Kotlin Academy incluye 4 lecciones en total.

¿Qué aprenderé en «catch y onCompletion: gestión de errores en Flow»?

Capture excepciones ascendentes y reaccione a los eventos de finalización del flujo. Practicas Kotlin Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar Kotlin Academy?

No se requiere experiencia previa. Kotlin Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 2 de 4.

¿Cuánto tiempo toma la lección «catch y onCompletion: gestión de errores en Flow»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de Kotlin Academy?

Sí. Cada lección de Kotlin Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. Operadores de Flow: map, filter, transform y take
  2. catch y onCompletion: gestión de errores en Flow
  3. combine y zip: combinar varios Flows
  4. flowOn y buffer: contexto y contrapresión
← Volver a Kotlin Academy