Sobes.tech
Junior

Wie behandelt man Ausnahmen in Kotlin richtig?

sobes.tech KI

Antwort von AI

In Kotlin wird die Ausnahmebehandlung mit der Konstruktion try...catch...finally durchgeführt. Es können Funktionen aufgerufen werden, die mit @Throws gekennzeichnet sind, um mit Java-Code zu interagieren.

fun readFile(path: String): String {
    return try {
        // Versuch, gefährlichen Code auszuführen
        java.io.File(path).readText()
    } catch (e: java.io.IOException) {
        // Behandlung einer spezifischen Ausnahme
        println("Fehler beim Lesen der Datei: ${e.message}")
        "" // Standardwert im Fehlerfall
    } finally {
        // Block, der immer ausgeführt wird, unabhängig von der Ausnahme
        println("Dateilesen beendet")
    }
}

Es können mehrere catch-Blöcke verwendet werden, um verschiedene Ausnahmearten zu behandeln:

fun processData(data: String) {
    try {
        // Code, der eine NumberFormatException oder NullPointerException auslösen kann
        val number = data.toInt()
        println("Zahl: $number")
    } catch (e: NumberFormatException) {
        println("Ungültiges Zahlenformat: ${e.message}")
    } catch (e: NullPointerException) {
        println("Null-Daten empfangen: ${e.message}")
    }
}

Kotlin hat keine checked-Exceptions wie Java. Funktionen können deklarieren, dass sie Ausnahmen werfen, indem sie @Throws verwenden, aber das ist in Kotlin-Code nicht verpflichtend.

Für Fälle, in denen eine Funktion Erfolg oder Fehler haben kann, werden häufig sealed classes oder der Result-Typ (in experimentellen Kotlin-Versionen) anstelle von Ausnahmen verwendet, insbesondere bei asynchronem Code.

Beispiel mit sealed class:

sealed class Result<out T>
data class Success<out T>(val value: T) : Result<T>()
data class Error(val exception: Throwable) : Result<Nothing>()

fun safelyDivide(a: Int, b: Int): Result<Int> {
    return try {
        if (b == 0) {
            throw ArithmeticException("Division durch Null")
        }
        Success(a / b)
    } catch (e: Throwable) {
        Error(e)
    }
}

// Verwendung:
fun processDivision() {
    when (val divisionResult = safelyDivide(10, 0)) {
        is Success -> println("Ergebnis: ${divisionResult.value}")
        is Error -> println("Fehler: ${divisionResult.exception.message}")
    }
}

Es ist wichtig, nur die Ausnahmen zu fangen, die behandelt werden können. Leere catch-Blöcke sollten vermieden werden. Bei Bedarf kann die Ausnahme in einem Log protokolliert werden.

Außerdem können Ausnahmen explizit mit throw geworfen werden:

fun requirePositive(number: Int) {
    if (number <= 0) {
        throw IllegalArgumentException("Die Zahl muss positiv sein")
    }
}