Исключения: сhecked или unchecked?



Сегодня пост о разнице между типами исключений и о том, какой тип выбрать для ошибок бизнес-логики.



Основы



🔸Checked исключения — наследники класса Exception:

class IOException extends Exception



Явно указываются в определении метода:

void write(int c) throws IOException



Код с обработкой исключения обязателен, иначе программа не скомпилируется



🔸Unchecked исключения — наследники класса RuntimeException:

class NullPointerException extends RuntimeException



О них не пишут в сигнатуре методов и редко ловят в блоке try-catch. Компилятор не предупредит о возможных ошибках, но иногда о них предупреждает IDE.



Оба типа можно поймать в блоке try-catch. Единственная техническая разница между checked и unchecked — обязательная обработка checked исключений. На уровне JVM разницы нет — производительность обоих типов одинакова.



За что отвечают стандартные исключения JDK



▫️ checked говорят об ошибках с "внешними" причинами: файл не найден, поток прервали, сокет закрыт, указанный класс не найден. Исключения показывают возможные проблемы, которые в будущем могут повториться



▫️ unchecked указывают на ошибки в коде: передали null вместо объекта, пришёл некорректный аргумент, нельзя привести объект к указанному типу. Исправляются при обнаружении, и в будущем такая ошибка не ожидается



Ошибки бизнес-логики



Не найден пользователь, не хватает прав, превышен лимит снятия денег со счёта. Какие это исключения: checked или unchecked?



В старых статьях по java и на многих курсах ответ однозначен. Исключения должны быть checked, чтобы ошибка не дошла до пользователя.



На JavaRush и в других статьях пишут, что checked исключения никто не использует, потому что это неудобно.



Кто же прав?



Исключения бизнес-логики — ожидаемые события, которые нужно обработать. Пользователь должен увидеть не стектрейс, а красивое сообщение💅



Многие фреймворки облегчают работу с исключениями. Если в Spring задать обработчик для UserNotFoundException, то туда попадут UserNotFoundException из любой части сервиса. Spring в любом случае их поймает, поэтому исключения бизнес-логики делают unchecked. Код получается гораздо чище.



По этой же причине checked иногда переводят в unchecked:

catch (SQLException e)

{ throw new IllegalStateException(e); }



Резюме

▫️ Если приложение написано на чистой java, то исключения бизнес-логики будут скорее всего checked

▫️ Если приложение использует фреймворк, который перехватывает исключения, их можно сделать unchecked



Правильные ответы на вопросы перед постом:

⭐️Вопрос 1: обработка checked исключений обязательна и проверяется на этапе компиляции

⭐️Вопрос 2: на практике чаще встречается

extends RuntimeException

но вариант extends Exception тоже ок