ПрограммированиеBackend разработчик (Kotlin)

Как устроена работа с исключениями (Exception Handling) в Kotlin? Чем отличается подход Kotlin от Java, как обрабатывать исключения, в чем нюансы с checked/unchecked exception, как влияет использование try/catch/finally?

Проходите собеседования с ИИ помощником Hintsage

Ответ.

В Kotlin обработка исключений реализована с помощью конструкции try/catch/finally, но отличается от подхода Java упором наUnchecked Exceptions и лаковым синтаксисом. Важное отличие — в Kotlin отсутствуют checked exceptions, что разгружает программиста от обязательного указания throws и перехвата таких исключений.

История вопроса

Java использует checked/unchecked exceptions, где checked требуют явного перехвата или объявления. Это часто приводит к избыточному бойлерплейту и неудобному коду. Kotlin задуман проще — все исключения, как правило, являются unchecked (унаследованные от RuntimeException), облегчая обработку и делая код более читаемым.

Проблема

Java-разработчики в Kotlin пытаются перехватывать и указывать checked exceptions — код компилируется, но смысл теряется. Кроме того, использование finally без осознания нюансов приводит к утечкам или неработающему коду.

Решение

Используем try/catch/finally в Kotlin кратко и по делу:

fun process(data: String): Int = try { data.toInt() } catch (e: NumberFormatException) { 0 } finally { println("Processing done") }
  • try/catch/finally может быть выражением, то есть возвращать значение, которое становится итоговым результатом функции или присваивается переменной.
  • Можно перехватывать несколько исключений, использовать when-переключение внутри catch для разной реакции на типы исключений.

Ключевые особенности:

  • Нет checked exceptions — не нужно объявлять или явно обрабатывать.
  • Конструкция try может работать как выражение (возвращает результат).
  • Можно использовать finally для завершающих действий (например, закрытия ресурсов), но не стоит выполнять операции, модифицирующие возвращаемое значение.

Вопросы с подвохом.

Что происходит, если исключение выброшено в блоке finally? Как это влияет на возврат значения?

Исключения, выброшенные из finally, всегда перекрывают любые другие исключения или return из блока try/catch, что может привести к потере важных данных о причине аварии.

fun demo(): Int = try { 1 } finally { throw RuntimeException("error in finally") }

Может ли try/catch быть выражением в Kotlin? В чем отличие от Java?

Да. try/catch/finally в Kotlin — это выражения, поэтому могут возвращать результат и быть использованы в местах, где допустимы значения.

val value = try { risky() } catch (e: Exception) { fallback() }

В Java это только операторы.

Обязательно ли перехватывать исключения в Kotlin, если вызывается сторонняя Java-функция с throws?

Нет. Так как checked exceptions игнорируются компилятором Kotlin: можно не перехватывать их явно, но они все равно могут быть брошены во время исполнения.

Типовые ошибки и анти-паттерны

  • Лишний перехват всех исключений (catch (e: Exception)) — ловим то, что не можем корректно обработать.
  • Неправильное использование finally — модификация возвращаемого значения или пробрасывание исключений.
  • Попытки использовать throws-объявления внутри Kotlin кода.

Пример из жизни

Негативный кейс

Вставляют catch (e: Exception) везде, не дифференцируя реальные и ожидаемые ошибки. Используют finally для возврата значения, что ведет к неожиданному поведению при ошибках.

Плюсы:

  • Весьма устойчивый к любым сбоям код

Минусы:

  • Трудно отлаживать
  • Теряются сообщения об ошибках и причина их возникновения
  • Скрываются реальные проблемы

Позитивный кейс

Используют перехват только ожидаемых ошибок, finally только для чистки ресурсов, а try/catch употребляют как выражения там, где это повышает читабельность.

Плюсы:

  • Легко читать, поддерживать и тестировать
  • Прозрачная обработка ошибок

Минусы:

  • Требует дисциплины при проектировании API и обработки исключений