Fehlerbehandlung in Kotlin: try/catch und mehr
Fehlerbehandlung ist ein wesentlicher Bestandteil der Erstellung von zuverlässigem und robustem Code. In Kotlin gibt es, wie in Java, den klassischen Mechanismus try/catch/finally, jedoch bietet die Sprache auch modernere, funktionale Ansätze. In diesem Artikel werden wir alle Methoden der Ausnahmebehandlung in Kotlin im Detail besprechen: vom grundlegenden try/catch bis hin zu elegantem runCatching und leistungsstarken Result und sealed class.
1. Klassisches try/catch/finally
Die grundlegende Syntax der Ausnahmebehandlung in Kotlin ist fast identisch mit Java, jedoch mit einem wichtigen Unterschied: try kann ein Ausdruck sein, also einen Wert zurückgeben.
Beispiel 1: try als Ausdruck
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}Beispiel 2: Mehrere catch-Blöcke
fun processInput(input: String) { try { val number = input.toInt() val result = 100 / number println("Ergebnis: $result") } catch (e: NumberFormatException) { println("Fehler: ungültiges Zahlenformat") } catch (e: ArithmeticException) { println("Fehler: Division durch Null") } finally { println("Der finally-Block wird immer ausgeführt") }}Der finally-Block wird in jedem Fall ausgeführt – sowohl bei erfolgreicher Ausführung als auch beim Auftreten einer Ausnahme. Dies ist praktisch für die Freigabe von Ressourcen (Schließen von Dateien, Verbindungen).
2. Elvis-Operator (?:) und sichere Aufrufe
Kotlin bietet eine elegante Möglichkeit zur Behandlung von null-Werten, die oft hilft, umständliche try/catch-Konstrukte zu vermeiden.
Beispiel: Sichere Konvertierung mit dem Elvis-Operator
fun safeStringToInt(input: String): Int { return input.toIntOrNull() ?: 0 // Wenn null, gib 0 zurück}
fun main() { println(safeStringToInt("42")) // 42 println(safeStringToInt("abc")) // 0}Die Funktion toIntOrNull() ist eine in Kotlin integrierte Alternative zu try/catch. Sie wirft keine Ausnahme, sondern gibt bei einem Fehler null zurück. Der Elvis-Operator ?: setzt einen Standardwert ein.
3. Funktionaler Ansatz: runCatching und Result
Modernes Kotlin empfiehlt die Verwendung eines funktionalen Stils der Fehlerbehandlung. Die wichtigsten Werkzeuge sind runCatching und die Klasse Result.
Beispiel: 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)
// Ergebnisverarbeitung successResult .onSuccess { println("Erfolg: $it") } // Erfolg: 5 .onFailure { println("Fehler: ${it.message}") }
failureResult .onSuccess { println("Erfolg: $it") } .onFailure { println("Fehler: ${it.message}") } // Fehler: / by zero
// Wert mit Standardwert abrufen val value1 = successResult.getOrDefault(-1) // 5 val value2 = failureResult.getOrDefault(-1) // -1
// Ergebnis transformieren val mappedResult = successResult.map { it * 2 } // Result(10)}Vorteile von runCatching:
- Der Code wird deklarativ und lesbar.
- Es ist nicht nötig, manuell
try/catchzu schreiben. - Das Ergebnis kann einfach kombiniert, transformiert und mit Methodenketten verarbeitet werden (
.map).