Когда и как создавать пользовательские исключения в Java?

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

Ответ

Создание пользовательских исключений:

1. Наследование:

  • От Exceptionпроверяемое (checked) исключение.
  • От RuntimeExceptionнепроверяемое (unchecked) исключение.

2. Когда создавать:

  • Для бизнес-логики (недостаточно средств, не найден заказ).
  • Для специфичных ошибок домена (InvalidTaxIdException).
  • Когда стандартные исключения не передают смысл ошибки.

3. Пример проверяемого исключения:

public class PaymentFailedException extends Exception {
    private final String transactionId;
    private final BigDecimal amount;

    public PaymentFailedException(String message, String transactionId, BigDecimal amount) {
        super(message);
        this.transactionId = transactionId;
        this.amount = amount;
    }

    public String getTransactionId() { return transactionId; }
    public BigDecimal getAmount() { return amount; }
}

// Использование
public void processPayment(PaymentRequest request) throws PaymentFailedException {
    if (!bankService.validate(request)) {
        throw new PaymentFailedException(
            "Bank declined transaction",
            request.getId(),
            request.getAmount()
        );
    }
}

4. Пример непроверяемого исключения:

public class ValidationException extends RuntimeException {
    private final Map<String, String> errors;

    public ValidationException(String message, Map<String, String> errors) {
        super(message);
        this.errors = Map.copyOf(errors);
    }

    public Map<String, String> getErrors() { return errors; }
}

// Использование в сервисе
public void registerUser(UserDto user) {
    Map<String, String> errors = validator.validate(user);
    if (!errors.isEmpty()) {
        throw new ValidationException("Invalid user data", errors);
    }
}

5. Best Practices:

  • Добавляйте конструкторы с причиной (cause) для цепочки исключений.
  • Не создавайте исключения для контроля потока выполнения.
  • Логируйте на уровне, где перехватываете исключение.
  • Документируйте в JavaDoc, когда метод бросает исключение.