По каким критериям в Java выбирают тип создаваемого пользовательского исключения (checked vs unchecked)?

«По каким критериям в Java выбирают тип создаваемого пользовательского исключения (checked vs unchecked)?» — вопрос из категории Java Core, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Выбор между checked (Exception) и unchecked (RuntimeException) для пользовательского исключения зависит от семантики ошибки и требований к обработке.

Критерии выбора

Критерий Checked исключение Unchecked исключение
Восстановимость Ошибка ожидаема, и есть разумная стратегия восстановления. Ошибка критична или указывает на баг; восстановление маловероятно.
Обязательность обработки Требуется явная обработка вызывающим кодом. Обработка опциональна, часто приводит к остановке потока/запроса.
Причина Внешние условия (отсутствующий файл, недоступный сервис). Нарушение контракта/логики (неверный аргумент, недопустимое состояние).
Влияние на API Усложняет сигнатуру метода (добавляет throws). Не влияет на сигнатуру метода.

Примеры создания

1. Checked исключение (обязательная обработка условия):

// Ошибка, от которой можно попытаться восстановиться (например, повторить запрос)
public class ServiceUnavailableException extends Exception {
    public ServiceUnavailableException(String message, Throwable cause) {
        super(message, cause);
    }
}
// Использование заставляет вызывающего решить, что делать при недоступности сервиса.

2. Unchecked исключение (ошибка программиста/валидации):

// Нарушение бизнес-правила, которое должно быть проверено до вызова метода
public class InsufficientFundsException extends RuntimeException {
    public InsufficientFundsException(double balance, double required) {
        super(String.format("Баланс %.2f недостаточен для списания %.2f", balance, required));
    }
}
// Использование: выбрасывается, если сумма списания > баланса.
// Обработка глобальная (например, на уровне контроллера).

Современный best practice: В enterprise-приложениях чаще создают unchecked-исключения для бизнес-ошибок, обрабатывая их централизованно (например, через @ControllerAdvice в Spring). Checked оставляют для действительно recoverable-ошибок, часто на границах системы (DAO, внешние вызовы).