Что такое unchecked exception (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 exceptions]]
- [[Что такое checked exception и когда его использовать]]
- [[В чём разница между Error и Exception]]
- [[Что такое stack trace]]
- [[Как правильно логировать исключения]]