Що таке checked виняток і коли його використовувати?
Використовуйте checked exception якщо:
Junior Level
Визначення
Checked exception (перевірюваний виняток) — це тип винятку, який компілятор Java зобов’язує обробити.
Навіщо: Java-дизайнери хотіли змусити розробника явно вирішити, як реагувати на передбачувані зовнішні збої – файл може бути відсутнім, мережа може зникнути. Без checked exceptions ці ситуації легко пропустити. Якщо метод може викинути checked виняток, ви повинні:
- Огорнути виклик у
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 виняток -- компілятор не пропустить.
// Рішення — обгортка
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 виняток кращий за unchecked? — Коли викликач може щось зробити (повторити, обрати альтернативний шлях)
Червоні прапорці (НЕ говорити):
- “Я пишу
throws Exceptionскрізь, щоб не думати” — це ламає контракт метода - “Checked exceptions — це проблема JVM, а не додатку” — ні, це помилки додатку
- “Я перехоплюю усі checked винятки і нічого не роблю” — мовчазне проковтування помилок
Пов’язані теми:
- [[В чому різниця між checked та unchecked винятками]]
- [[Що таке unchecked виняток (Runtime Exception)]]
- [[Які винятки потрібно обробляти обов’язково]]
- [[Що знаходиться на вершині ієрархії винятків]]
- [[Що таке Throwable]]