Исключения

Классы исключений

Все исключения в Kotlin являются наследниками класса Throwable. У каждого исключения есть сообщение, трассировка стека, а также причина, по которой это исключение вероятно было вызвано.

Для того, чтобы возбудить исключение явным образом, используйте оператор throw

throw MyException("Hi There!")

Оператор try позволяет перехватывать исключения

try {
    // some code
}
catch (e: SomeException) {
    // handler
}
finally {
    // optional finally block
}

В коде может быть любое количество блоков catch (такие блоки могут и вовсе отсутствовать). Блоки finally могут быть опущены. Однако, должен быть использован как минимум один блок catch или finally.

Try - это выражение

Ключевое слово try является выражением, то есть оно может иметь возвращаемое значение.

val a: Int? = try { parseInt(input) } catch (e: NumberFormatException) { null }

Возвращаемым значением будет либо последнее выражение в блоке try, либо последнее выражение в блоке catch (или блоках). Содержимое finally блока никак не повлияет на результат try-выражения.

Проверяемые исключения

В языке Kotlin нет проверяемых исключений. Для этого существует целый ряд причин, но мы рассмотрим простой пример.

Приведённый ниже фрагмент кода является примером простого интерфейса в JDK, который реализован в классе StringBulder

Appendable append(CharSequence csq) throws IOException;

О чём говорит нам сигнатура? О том, что каждый раз, когда я присоединяю строку к чему-то (к StringBuilder, какому-нибудь логу, сообщению в консоль и т.п) , мне необходимо отлавливать исключения типа IOExceptions. Почему? Потому, что данная операция может вызывать IO (Input-Output: Ввод-Вывод) (Writer также реализует интерфейс Appendable)... Данный факт постоянно приводит к написанию подобного кода:

try {
    log.append(message)
}
catch (IOException e) {
    // Должно быть безопасно
}

И это плохо. См. Effective Java, Item 65: Don't ignore exceptions (не игнорируйте исключения).

Брюс Эккель как-то сказал в своей статье "Нужны ли в Java проверяемые исключения?"(Does Java need Checked Exceptions?):

Анализ небольших программ показал, что обязательная обработка исключений может повысить производительность разработчика и улучшить качество кода. Однако, изучение крупных проектов по разработке программного обеспечения позволяет сделать противоположный вывод: происходит понижение продуктивности и сравнительно небольшое улучшение кода (а иногда и без всякого улучшения).

Другие цитаты подобного рода:

Тип Nothing

Вы можете использовать выражение throw в качестве части элвис-выражения:

val s = person.name ?: throw IllegalArgumentException("Name required")

Типом выражения throw является специальный тип под названием Nothing. У этого типа нет никаких значений, он используетя для того, чтобы обозначить те участки кода, которые могут быть не достигнуты никогда. В своём коде вы можете использовать Nothing для того, чтобы отметить функцию, чей результат никогда не будет возвращён:

fun fail(message: String): Nothing {
    throw IllegalArgumentException(message)
}

При вызове такой функции компилятор будет в курсе, что исполнения кода далее не последует:

val s = person.name ?: fail("Name required")
println(s)     // известно, что переменная 's' проинициализирована к этому моменту

Совместимость с Java

См. раздел, посвещённый исключениям, в "Совместимости с Java" Java Interoperability section.