Tratamento de Erros em Kotlin: try/catch e muito mais
O tratamento de erros é uma parte essencial para escrever código confiável e robusto. Em Kotlin, assim como em Java, existe o mecanismo clássico try/catch/finally, no entanto, a linguagem oferece abordagens mais modernas e funcionais. Neste artigo, vamos detalhar todas as formas de tratar exceções em Kotlin: desde o básico try/catch até o elegante runCatching e os poderosos Result e sealed class.
1. Clássico try/catch/finally
A sintaxe básica do tratamento de exceções em Kotlin é praticamente idêntica ao Java, mas com uma diferença importante: try pode ser uma expressão, ou seja, pode retornar um valor.
Exemplo 1: try como expressão
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}Exemplo 2: Múltiplos blocos catch
fun processInput(input: String) { try { val number = input.toInt() val result = 100 / number println("Resultado: $result") } catch (e: NumberFormatException) { println("Erro: formato de número inválido") } catch (e: ArithmeticException) { println("Erro: divisão por zero") } finally { println("O bloco finally é sempre executado") }}O bloco finally é executado em qualquer caso — tanto na execução bem-sucedida quanto na ocorrência de uma exceção. Isso é útil para liberar recursos (fechar arquivos, conexões).
2. Operador Elvis (?:) e chamadas seguras
Kotlin oferece uma forma elegante de lidar com valores null, que muitas vezes ajuda a evitar construções verbosas de try/catch.
Exemplo: Conversão segura com operador Elvis
fun safeStringToInt(input: String): Int { return input.toIntOrNull() ?: 0 // Se null, retorna 0}
fun main() { println(safeStringToInt("42")) // 42 println(safeStringToInt("abc")) // 0}A função toIntOrNull() é uma alternativa embutida no Kotlin ao try/catch. Ela não lança uma exceção, mas retorna null em caso de erro. O operador Elvis ?: fornece um valor padrão.
3. Abordagem funcional: runCatching e Result
O Kotlin moderno recomenda o uso do estilo funcional para tratamento de erros. As ferramentas-chave são runCatching e a classe Result.
Exemplo: 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)
// Tratamento do resultado successResult .onSuccess { println("Sucesso: $it") } // Sucesso: 5 .onFailure { println("Erro: ${it.message}") }
failureResult .onSuccess { println("Sucesso: $it") } .onFailure { println("Erro: ${it.message}") } // Erro: / by zero
// Obtendo valor com padrão val value1 = successResult.getOrDefault(-1) // 5 val value2 = failureResult.getOrDefault(-1) // -1
// Transformando o resultado val mappedResult = successResult.map { it * 2 } // Result(10)}Vantagens do runCatching:
- O código se torna declarativo e legível.
- Não é necessário escrever
try/catchmanualmente. - O resultado pode ser facilmente combinado, transformado e processado em cadeias de chamadas (
.map