Що таке unchecked виняток (Runtime Exception)?
Базові unchecked винятки (NPE, IllegalArgumentException) сигналізують про баги. Проте доменні unchecked винятки (UserNotFoundException, OrderAlreadyExistsException) -- це очікув...
Junior Level
Визначення
Unchecked exceptions (неперевірювані винятки) — це винятки, які успадковуються від RuntimeException. Компілятор не вимагає їх обробляти.
Ієрархія
Throwable
└── Exception
└── RuntimeException ← unchecked
├── NullPointerException
├── IllegalArgumentException
├── IndexOutOfBoundsException
├── ArithmeticException
└── ClassCastException
Приклади
// NullPointerException — найчастіший
String s = null;
s.length(); // NPE
// IllegalArgumentException
public void setAge(int age) {
if (age < 0) throw new IllegalArgumentException("Age must be positive");
}
// ArithmeticException
int x = 10 / 0; // ArithmeticException
Коли виникають
- Помилки програмування (null, невірні аргументи)
- Порушення контрактів методів
- Логічні помилки в коді
Чи потрібно обробляти?
Базові unchecked винятки (NPE, IllegalArgumentException) сигналізують про баги. Проте доменні unchecked винятки (UserNotFoundException, OrderAlreadyExistsException) – це очікувані бізнес-ситуації, а не баги.
Middle Level
Коли НЕ використовувати unchecked винятки
- Публічні бібліотеки для сторонніх розробників – checked винятки накладають корисну обробку
- Команда без культури обробки помилок – checked = страховка від забуття
- Критичні системи – якщо ігнорування помилки = фінансові втрати, checked змусять обробити
Under the Hood: fillInStackTrace()
Головна “ціна” винятку — нативний метод fillInStackTrace(), який обходить стек потоку. У високонавантажених системах (100k+ RPS) генерація винятків може забирати 20-30% CPU.
Fail-Fast принцип
Fail-Fast – принцип: помилка повинна проявитися якомога раніше, а не «протікати» через 10 шарів коду. NPE на рядку s.length() миттєво вказує на проблему, а не «спливе» через годину роботи.
Unchecked винятки — ідеальний інструмент для реалізації Fail-Fast:
public User findUser(Long id) {
Objects.requireNonNull(id, "ID cannot be null");
// Якщо null — впадемо одразу, а не через 10 шарів
return repository.findById(id)
.orElseThrow(() -> new UserNotFoundException("User not found: " + id));
}
Централізована обробка
У Spring Boot використовується @ControllerAdvice + @ExceptionHandler:
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(UserNotFoundException.class)
public ResponseEntity<ErrorResponse> handleNotFound(UserNotFoundException e) {
return ResponseEntity.status(404)
.body(new ErrorResponse("USER_NOT_FOUND", e.getMessage()));
}
@ExceptionHandler(ValidationException.class)
public ResponseEntity<ErrorResponse> handleValidation(ValidationException e) {
return ResponseEntity.status(400)
.body(new ErrorResponse("VALIDATION_ERROR", e.getMessage()));
}
}
// Потік: Виняток «спливає» через усі шари сервісу →
// Spring знаходить @ExceptionHandler з підходящим типом →
// Викликає метод → ResponseEntity перетворюється на JSON-відповідь.
Чому Spring пішов в unchecked
- Чистота коду — без
try-catchшуму - Централізована обробка — усі помилки спливають до
@ControllerAdvice - Reactive programming — у Project Reactor checked винятки практично неможливі
Senior Level
Продуктивність та оптимізація
Pre-instantiated Exceptions — для часто виникаючих помилок можна створити синглтон-виняток без стек-трейсу:
public static final ValidationException INVALID_FORMAT =
new ValidationException("Invalid format", null, false, false);
Цей виняток не створює навантаження на GC, але ускладнює дебаг (немає стек-трейсу).
Control Flow антипатерн
Ніколи не використовуйте винятки для управління логікою:
// ПОГАНО — повільно і нечитабельно
try {
User user = findUser(id);
} catch (UserNotFoundException e) {
// перехід до наступного кроку
}
// ДОБРЕ
Optional<User> user = findUser(id);
if (user.isPresent()) { ... }
Повернення Optional у 100-1000 разів швидше, ніж кидання винятку.
Error vs RuntimeException
Не плутайте їх:
- Error — проблеми JVM (
OutOfMemoryError,StackOverflowError). Ловити — погана практика - RuntimeException — помилки додатку. Обробляти централізовано
Swallowing Exceptions
Найгірший злочин:
catch (RuntimeException e) { } // Мовчки ковтає баг
Діагностика та моніторинг
- Micrometer — рахуйте кількість
RuntimeException. Різкий ріст NPE — привід для відкату деплою - Log Enrichment — логуйте контекст (
userId,orderId), а не лише стек-трейс - Metric-driven Exception Tracking — алертинг на аномалії у винятках
🎯 Шпаргалка для співбесіди
Обов’язково знати:
- Unchecked exceptions успадковуються від
RuntimeException, компілятор не вимагає обробки - Базові unchecked (NPE, IllegalArgumentException) сигналізують про баги; доменні (
UserNotFoundException) — про бізнес-ситуації - Fail-Fast — помилка повинна проявитися якомога раніше
- Spring Boot обробляє unchecked централізовано через
@ControllerAdvice+@ExceptionHandler fillInStackTrace()— найдорожча частина, може забирати 20-30% CPU при 100k+ RPS- Преінстанційовані винятки (синглтони) знижують навантаження на GC
- Ніколи не використовувати винятки для control flow —
Optionalу 100-1000 разів швидше - Swallowing exceptions (
catch (RuntimeException e) {}) — найгірший злочин
Часті уточнюючі запитання:
- Чому Spring надає перевагу unchecked exceptions? — Чистота коду, централізована обробка через
@ControllerAdvice, сумісність з Reactive programming - Коли unchecked винятки НЕ рекомендуються? — Публічні бібліотеки, команда без культури обробки помилок, критичні фінансові системи
- Як прискорити створення частих винятків? — Pre-instantiated exceptions з
writableStackTrace = false - Чим Error відрізняється від RuntimeException? — Error — проблеми JVM (не ловити), RuntimeException — помилки додатку (обробляти централізовано)
Червоні прапорці (НЕ говорити):
- “Я використовую винятки для управління бізнес-логікою” — це антипатерн, повільно і нечитабельно
- “Unchecked винятки не потрібно обробляти взагалі” — потрібно, але централізовано
- “Мовчазне проковтування RuntimeException — нормальна практика” — це приховує баги
Пов’язані теми:
- [[В чому різниця між checked та unchecked винятками]]
- [[Що таке checked виняток і коли його використовувати]]
- [[В чому різниця між Error та Exception]]
- [[Що таке stack trace]]
- [[Як правильно логувати винятки]]