Назад к вопросам
Junior
105
questionbank

Как правильно обрабатывать исключения в Kotlin?

Sobes Copilot

Получайте ответы в реальном времени

Ответ от нейросети

sobes.tech 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) instead of исключений, особенно в асинхронном коде.

Пример с 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("Число должно быть положительным")
    }
}