Sobes.tech
Junior

Как правилно да обработваме изключения в Kotlin?

sobes.tech AI

Отговор от AI

В Kotlin за обработката на изключения се използва конструкцията try...catch...finally. Може да се извикват функции, маркирани с @Throws, за взаимодействие с Java код.

fun readFile(path: String): String {
    return try {
        // Опит за изпълнение на опасен код
        java.io.File(path).readText()
    } catch (e: java.io.IOException) {
        // Обработка на конкретно изключение
        println("Грешка при четене на файла: ${e.message}")
        "" // Връщане на стойност по подразбиране при грешка
    } finally {
        // Блок, който се изпълнява винаги, независимо от изключението
        println("Завърши опит за четене на файл")
    }
}

Може да се използват няколко блока catch за обработка на различни типове изключения:

fun processData(data: String) {
    try {
        // Код, който може да предизвика NumberFormatException или NullPointerException
        val number = data.toInt()
        println("Число: $number")
    } catch (e: NumberFormatException) {
        println("Невалиден формат на число: ${e.message}")
    } catch (e: NullPointerException) {
        println("Получени нулеви данни: ${e.message}")
    }
}

Kotlin няма checked-изключения като в Java. Функциите могат да обявяват, че могат да хвърлят изключения с @Throws, но това не е задължително за Kotlin код.

За случаи, когато функция може да завърши успешно или с грешка, често се използват sealed класове или Result тип (в експериментални версии на Kotlin) вместо изключения, особено в асинхронен код.

Пример с sealed клас:

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("Деление на нула")
        }
        Success(a / b)
    } catch (e: Throwable) {
        Error(e)
    }
}

// Използване:
fun processDivision() {
    when (val divisionResult = safelyDivide(10, 0)) {
        is Success -> println("Резултат: ${divisionResult.value}")
        is Error -> println("Грешка: ${divisionResult.exception.message}")
    }
}

Важно е да се хващат само тези изключения, които можете да обработите. Не е препоръчително да се оставят празни блокове catch. При необходимост, може да се запише информация за изключението в лог.

Може също така да се хвърлят изключения явно с throw:

fun requirePositive(number: Int) {
    if (number <= 0) {
        throw IllegalArgumentException("Числото трябва да е положително")
    }
}