← Назад к вопросам

Какой базовый тип исключения выбрать для случая, когда переданный объект не подходит для проверки в сервисе?

1.0 Junior🔥 111 комментариев
#SOLID и паттерны проектирования#Безопасность#Основы Java

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Выбор типа исключения для некорректных объектов

Вопрос о правильном выборе типа исключения — это вопрос о чистоте архитектуры и правильной обработке ошибок. Для случая, когда переданный объект не подходит для обработки в сервисе, есть несколько вариантов.

Правильный выбор: IllegalArgumentException

IllegalArgumentException — это оптимальный выбор в большинстве случаев, когда переданный аргумент не подходит для метода:

public class UserValidator {
    
    public void validateUser(User user) {
        if (user == null) {
            throw new IllegalArgumentException("User cannot be null");
        }
        
        if (user.getId() <= 0) {
            throw new IllegalArgumentException("User ID must be positive");
        }
        
        if (user.getEmail() == null || user.getEmail().isEmpty()) {
            throw new IllegalArgumentException("User email is required");
        }
    }
}

Иерархия исключений Java

Throwable
├── Exception
│   ├── RuntimeException (unchecked)
│   │   ├── IllegalArgumentException
│   │   ├── NullPointerException
│   │   ├── IllegalStateException
│   │   └── ...
│   └── IOException (checked)
│       └── ...
└── Error
    ├── OutOfMemoryError
    └── StackOverflowError

Типы исключений и когда их использовать

1. IllegalArgumentException (РЕКОМЕНДУЕТСЯ)

Используй когда параметры метода некорректны:

public class PaymentService {
    
    public void processPayment(BigDecimal amount, String currency) {
        // Проверка параметров
        if (amount == null || amount.compareTo(BigDecimal.ZERO) <= 0) {
            throw new IllegalArgumentException(
                "Amount must be greater than zero, got: " + amount
            );
        }
        
        if (currency == null || currency.isEmpty()) {
            throw new IllegalArgumentException("Currency is required");
        }
        
        if (!isValidCurrency(currency)) {
            throw new IllegalArgumentException(
                "Invalid currency: " + currency
            );
        }
        
        // Обработка платежа
    }
}

2. NullPointerException (только в edge cases)

Травня генерировать явно редко, но иногда полезно для debug-а:

public void processData(Object obj) {
    if (obj == null) {
        // Не рекомендуется
        throw new NullPointerException("Object cannot be null");
        
        // Лучше
        throw new IllegalArgumentException("Object cannot be null");
    }
}

3. IllegalStateException

Используй когда объект находится в неправильном состоянии, не для параметров:

public class Order {
    private OrderStatus status = OrderStatus.PENDING;
    
    public void cancelOrder() {
        if (status == OrderStatus.SHIPPED) {
            throw new IllegalStateException(
                "Cannot cancel order that is already shipped"
            );
        }
        this.status = OrderStatus.CANCELLED;
    }
}

4. ClassCastException

Используй когда неправильный тип данных:

public void processObject(Object obj) {
    if (!(obj instanceof User)) {
        throw new ClassCastException(
            "Expected User, but got " + obj.getClass().getName()
        );
    }
    User user = (User) obj;
}

Практический пример: валидация в сервисе

@Service
public class UserService {
    
    /**
     * Создаёт нового пользователя
     * @param user объект пользователя
     * @throws IllegalArgumentException если user имеет некорректные данные
     */
    public User createUser(User user) {
        // Проверка объекта
        if (user == null) {
            throw new IllegalArgumentException("User object cannot be null");
        }
        
        // Проверка полей
        if (user.getEmail() == null || user.getEmail().trim().isEmpty()) {
            throw new IllegalArgumentException("Email is required");
        }
        
        if (!isValidEmail(user.getEmail())) {
            throw new IllegalArgumentException(
                "Invalid email format: " + user.getEmail()
            );
        }
        
        if (user.getAge() < 0 || user.getAge() > 150) {
            throw new IllegalArgumentException(
                "Age must be between 0 and 150, got: " + user.getAge()
            );
        }
        
        // Проверка состояния
        if (userExists(user.getEmail())) {
            throw new IllegalStateException(
                "User with email " + user.getEmail() + " already exists"
            );
        }
        
        // Сохранение
        return userRepository.save(user);
    }
}

Кастомные исключения (расширенный подход)

Для более сложных сценариев можно создавать кастомные исключения:

// Кастомное исключение для бизнес-логики
public class InvalidUserException extends IllegalArgumentException {
    public InvalidUserException(String message) {
        super(message);
    }
    
    public InvalidUserException(String message, Throwable cause) {
        super(message, cause);
    }
}

// Использование
public class UserValidator {
    public void validate(User user) throws InvalidUserException {
        if (user == null) {
            throw new InvalidUserException("User cannot be null");
        }
        // ... другие проверки
    }
}

Правила выбора исключения

СитуацияИсключениеПример
Параметр null или некорректенIllegalArgumentExceptionamount <= 0
Неправильный тип объектаClassCastExceptionожидается User, получен String
Объект в неправильном состоянииIllegalStateExceptionпопытка отменить уже отправленный заказ
Логическая ошибка (не ожидаемое)IllegalStateExceptionне инициализирована нужная переменная
Операция невозможнаUnsupportedOperationExceptionметод не реализован

Лучшие практики

1. Выбирай наиболее специфичное исключение

// ❌ Слишком общее
throw new Exception("User validation failed");

// ✅ Специфичное
throw new IllegalArgumentException("User email is invalid: " + email);

2. Добавляй описательное сообщение об ошибке

// ❌ Неинформативно
throw new IllegalArgumentException("Invalid user");

// ✅ Информативно
throw new IllegalArgumentException(
    "User email must not be empty, got: '" + email + "'"
);

3. Включай контекст ошибки

throw new IllegalArgumentException(
    String.format(
        "User age must be between %d and %d, got %d",
        MIN_AGE, MAX_AGE, age
    )
);

4. Проверяй параметры в начале метода

public void processUser(User user) {
    // Проверки в начале
    if (user == null) {
        throw new IllegalArgumentException("User cannot be null");
    }
    
    // Логика после проверок
    // ...
}

Заключение

Для большинства случаев, когда переданный объект не подходит для проверки в сервисе, используй IllegalArgumentException. Это стандартное исключение, которое явно говорит что проблема в параметрах метода. Для более специфичных случаев (состояние объекта, тип данных) выбирай соответствующее исключение из иерархии RuntimeException.

Какой базовый тип исключения выбрать для случая, когда переданный объект не подходит для проверки в сервисе? | PrepBro