Manejo de errores en Kotlin: try/catch y más
El manejo de errores es una parte esencial para escribir código robusto y confiable. En Kotlin, al igual que en Java, existe el mecanismo clásico try/catch/finally, sin embargo, el lenguaje ofrece enfoques más modernos y funcionales. En este artículo, analizaremos en detalle todas las formas de manejar excepciones en Kotlin: desde el try/catch básico hasta el elegante runCatching y los potentes Result y sealed class.
1. Clásico try/catch/finally
La sintaxis básica del manejo de excepciones en Kotlin es prácticamente idéntica a Java, pero con una diferencia importante: try puede ser una expresión, es decir, puede devolver un valor.
Ejemplo 1: try como expresión
fun parseIntOrNull(input: String): Int? { return try { input.toInt() } catch (e: NumberFormatException) { null }}
fun main() { val result = parseIntOrNull("123") println(result) // 123
val badResult = parseIntOrNull("abc") println(badResult) // null}Ejemplo 2: Múltiples bloques catch
fun processInput(input: String) { try { val number = input.toInt() val result = 100 / number println("Resultado: $result") } catch (e: NumberFormatException) { println("Error: formato de número inválido") } catch (e: ArithmeticException) { println("Error: división por cero") } finally { println("El bloque finally siempre se ejecuta") }}El bloque finally se ejecuta en cualquier caso — tanto en ejecución exitosa como cuando ocurre una excepción. Esto es útil para liberar recursos (cerrar archivos, conexiones).
2. Operador Elvis (?:) y llamadas seguras
Kotlin ofrece una forma elegante de manejar valores null, que a menudo ayuda a evitar construcciones try/catch engorrosas.
Ejemplo: Conversión segura con operador Elvis
fun safeStringToInt(input: String): Int { return input.toIntOrNull() ?: 0 // Si es null, devolvemos 0}
fun main() { println(safeStringToInt("42")) // 42 println(safeStringToInt("abc")) // 0}La función toIntOrNull() es una alternativa integrada en Kotlin a try/catch. No lanza una excepción, sino que devuelve null en caso de error. El operador Elvis ?: proporciona un valor por defecto.
3. Enfoque funcional: runCatching y Result
El Kotlin moderno recomienda usar un estilo funcional para el manejo de errores. Las herramientas clave son runCatching y la clase Result.
Ejemplo: runCatching
import kotlin.Result
fun divide(a: Int, b: Int): Result<Int> { return runCatching { a / b }}
fun main() { val successResult = divide(10, 2) val failureResult = divide(10, 0)
// Manejo del resultado successResult .onSuccess { println("Éxito: $it") } // Éxito: 5 .onFailure { println("Error: ${it.message}") }
failureResult .onSuccess { println("Éxito: $it") } .onFailure { println("Error: ${it.message}") } // Error: / by zero
// Obtener valor con valor por defecto val value1 = successResult.getOrDefault(-1) // 5 val value2 = failureResult.getOrDefault(-1) // -1
// Transformación del resultado val mappedResult = successResult.map { it * 2 } // Result(10)}Ventajas de runCatching:
- El código se vuelve declarativo y legible.
- No es necesario escribir
try/catchmanualmente. - El resultado se puede combinar, transformar y procesar fácilmente con cadenas de llamadas (
.map).