Исключения
Классы исключений
Все исключения в 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?):
Анализ небольших программ показал, что обязательная обработка исключений может повысить производительность разработчика и улучшить качество кода. Однако, изучение крупных проектов по разработке программного обеспечения позволяет сделать противоположный вывод: происходит понижение продуктивности и сравнительно небольшое улучшение кода (а иногда и без всякого улучшения).
Другие цитаты подобного рода:
- Java's checked exceptions were a mistake (Rod Waldhoff)
- The Trouble with Checked Exceptions (Anders Hejlsberg)
Тип 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.