Исключения

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

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

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

throw Exception("Hi There!")

Чтобы перехватить исключение, используйте выражение try...catch.

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

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

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

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

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

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

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

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

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

Appendable append(CharSequence csq) throws IOException;

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

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

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

Брюс Эккель как-то сказал о проверяемых исключения:

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

Вот несколько других рассуждений по этому поводу:

Если вы хотите предупредить вызывающие объекты о возможных исключениях при вызове Kotlin кода из Java, Swift или Objective-C, вы можете использовать аннотацию @Throws. Узнайте больше об использовании этой аннотации для Java, а также для Swift и Objective-C.

Тип Nothing

throw в Kotlin является выражением, поэтому есть возможность использовать его, например, в качестве части Elvis-выражения:

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' проинициализирована к этому моменту

Вы также можете столкнуться с этим типом при работе с выводом типов. Nullable-вариант этого типа Nothing? имеет ровно одно возможное значение - null. Если вы используете null для инициализации значения предполагаемого типа, и нет никакой другой информации, которую можно использовать для определения более конкретного типа, компилятор определит тип Nothing?.

val x = null           // у 'x' тип `Nothing?`
val l = listOf(null)   // у 'l' тип `List<Nothing?>

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

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