Что такое checked exception и когда его использовать?
Используйте checked exception если:
Junior Level
Определение
Checked exception (проверяемое исключение) — это тип исключения, который компилятор Java обязывает обработать.
Зачем: Java-дизайнеры хотели заставить разработчика явно решить, как реагировать на предсказуемые внешние сбои – файл может отсутствовать, сеть может пропасть. Без checked exceptions эти ситуации легко пропустить. Если метод может выбросить checked exception, вы должны:
- Обернуть вызов в
try-catch - Или добавить
throwsв сигнатуру метода
Примеры
// Компилятор заставит обработать IOException
public String readFile() throws IOException {
return Files.readString(Paths.get("data.txt"));
}
// Обязаны обработать
public void safeRead() {
try {
Files.readString(Paths.get("data.txt"));
} catch (IOException e) {
System.err.println("Failed to read: " + e.getMessage());
}
}
Когда использовать
Используйте checked exception если:
- Сбой ожидаем — файл может отсутствовать, сеть может пропасть
- Сбой восстановим — можно повторить попытку, попробовать другой путь
- Это критично — нельзя просто “забыть” об этой ситуации
Распространённые checked исключения
IOException— проблемы ввода-выводаSQLException— ошибки базы данныхClassNotFoundException— класс не найденInterruptedException— поток прерван
Middle Level
Что выбрать: throws или try-catch?
- throws – когда метод не может принять решение об обработке. Пусть вызывающий решает.
- try-catch – когда можете обработать на месте: залогировать, вернуть дефолтное значение, повторить запрос.
Механизм компиляции
Компилятор javac проверяет граф вызовов. Если где-то в цепочке вызывается метод с checked исключением и оно не обработано, компиляция прервётся.
Exception Translation
В крупных проектах с многослойной архитектурой проброс checked исключений нарушает инкапсуляцию слоёв. В небольших проектах допустимо пробрасывать их наверх.
public Order createOrder(Order order) {
try {
return orderRepository.save(order);
} catch (SQLException e) {
throw new OrderStorageException("Failed to save order", e);
}
}
OrderStorageException — это runtime исключение. Бизнес-логика не зависит от JDBC.
Три условия использования checked exceptions
- Сбой ожидаем — не баг в коде, а внешнее обстоятельство
- Сбой восстановим — вызывающий код может что-то предпринять
- Критично для бизнеса — нельзя проигнорировать
Lambda и checked exceptions
Функциональные интерфейсы не поддерживают checked исключения:
// Не скомпилируется!
list.stream().map(path -> Files.readString(path))
// Почему: интерфейс Function<T,R> не объявляет throws в сигнатуре apply().
// Поэтому лямбда не может пробросить checked exception -- компилятор не пропустит.
// Решение — обёртка
list.stream().map(path -> {
try {
return Files.readString(path);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
})
Senior Level
Under the Hood: атрибут Exceptions
В .class файле информация о throws сохраняется в атрибуте метода Exceptions. JVM не использует его для контроля в рантайме — только для верификатора компилятора.
Binary Compatibility
Добавление checked исключения в метод существующей библиотеки ломает бинарную совместимость. Все клиенты перестанут компилироваться.
Удаление исключения — бинарно совместимо, но оставляет лишний код у клиентов.
Overriding и LSP
Принцип подстановки Лисков диктует правила:
- Метод-наследник может не выбрасывать исключения родителя
- Может выбрасывать подтипы исключений родителя
- НЕ может выбрасывать новые checked исключения
Производительность
Checked исключение — это всё ещё Throwable с дорогим fillInStackTrace(). Для частых “ожидаемых” ситуаций лучше возвращать Optional<T> или Result-объекты.
Edge Cases
- InterruptedException — “хорошее” checked исключение. При перехвате восстанавливайте статус:
Thread.currentThread().interrupt() - Generic Throws — Java позволяет
public <E extends Exception> void doWork() throws E - throws Exception — никогда не пишите так в публичном API
Мониторинг
Не бросайте Exception или Throwable. Создавайте свои типы для чёткого разделения ошибок в Micrometer/Prometheus.
🎯 Шпаргалка для интервью
Обязательно знать:
- Checked exception — компилятор обязывает обработать (
try-catchилиthrows) - Использовать, если сбой ожидаем, восстановим и критичен для бизнеса
- Распространённые:
IOException,SQLException,ClassNotFoundException,InterruptedException throws— когда метод не может решить, как обработать;try-catch— когда можете- Exception Translation — оборачивание checked в доменное unchecked для слоёв архитектуры
- Lambda не поддерживает checked исключения — нужна обёртка в
UncheckedIOException - Добавление checked исключения ломает бинарную совместимость библиотеки
- При overriding метод-наследник НЕ может добавлять новые checked исключения (LSP)
Частые уточняющие вопросы:
- Почему checked исключения не работают с лямбдами? — Функциональные интерфейсы (
Function,Predicate) не объявляютthrowsв сигнатуре - Что будет при добавлении checked исключения в публичный API библиотеки? — Все клиенты перестанут компилироваться — ломает бинарную совместимость
- Как правильно обработать InterruptedException? — Перехватить и восстановить статус:
Thread.currentThread().interrupt() - Когда checked exception лучше unchecked? — Когда вызывающий может что-то предпринять (повторить, выбрать альтернативный путь)
Красные флаги (НЕ говорить):
- “Я пишу
throws Exceptionвезде, чтобы не думать” — это ломает контракт метода - “Checked exceptions — это проблема JVM, а не приложения” — нет, это ошибки приложения
- “Я перехватываю все checked исключения и ничего не делаю” — молчаливое проглатывание ошибок
Связанные темы:
- [[В чём разница между checked и unchecked exceptions]]
- [[Что такое unchecked exception (Runtime Exception)]]
- [[Какие исключения нужно обрабатывать обязательно]]
- [[Что находится в вершине иерархии исключений]]
- [[Что такое Throwable]]