Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Стратегия выбора исключений в Java
Основной принцип
Выбор исключения зависит от типа ошибки, её критичности и возможности восстановления. Java разделяет исключения на иерархию, и правильный выбор типа помогает коду быть понятнее и легче обрабатываться.
Иерархия исключений
Throwable
├── Error (критичные, не ловим обычно)
│ ├── OutOfMemoryError
│ ├── StackOverflowError
│ └── VirtualMachineError
└── Exception
├── Checked Exceptions (ОБЯЗАТЕЛЬНО ловить или объявлять)
│ ├── IOException
│ ├── SQLException
│ ├── FileNotFoundException
│ └── ParseException
└── Unchecked Exceptions / RuntimeException (необязательно ловить)
├── NullPointerException
├── IllegalArgumentException
├── IllegalStateException
├── IndexOutOfBoundsException
└── ArithmeticException
Checked vs Unchecked Exceptions
public class ExceptionTypes {
// Checked Exception - ОБЯЗАТЕЛЬНО ловим или объявляем
public void readFile(String filename) throws IOException {
FileReader reader = new FileReader(filename);
// Если файл не найден - IOException
}
// Unchecked Exception - можем не ловить
public int divide(int a, int b) {
// Если b == 0 - ArithmeticException (не обязательно объявлять)
return a / b;
}
public void processArray(int[] arr, int index) {
// Если index >= arr.length - ArrayIndexOutOfBoundsException
int value = arr[index];
}
}
Когда создавать свои исключения?
// ✅ Создавай свои исключения, если нужна специфичность
public class UserNotFoundException extends RuntimeException {
private Long userId;
public UserNotFoundException(Long userId) {
super("User with id " + userId + " not found");
this.userId = userId;
}
public Long getUserId() {
return userId;
}
}
// ❌ Плохо: используешь generic Exception
public User getUserById(Long id) throws Exception {
if (id == null) {
throw new Exception("ID is null");
}
// ...
}
// ✅ Хорошо: используешь специфичное исключение
public User getUserById(Long id) {
if (id == null) {
throw new IllegalArgumentException("ID cannot be null");
}
// ...
}
Таблица выбора исключений
Для валидации входных параметров:
public void setAge(int age) {
if (age < 0 || age > 150) {
// IllegalArgumentException - для некорректного аргумента
throw new IllegalArgumentException("Age must be between 0 and 150");
}
this.age = age;
}
public void process(List<String> items) {
if (items == null) {
// NullPointerException - явно проверяем null
throw new NullPointerException("items cannot be null");
}
// ...
}
Для состояния объекта:
public class BankAccount {
private boolean closed = false;
public void withdraw(BigDecimal amount) {
if (closed) {
// IllegalStateException - объект в неправильном состоянии
throw new IllegalStateException("Account is closed");
}
// ...
}
}
public class PaymentProcessor {
private State state = State.IDLE;
public void process(Payment payment) {
if (state != State.READY) {
throw new IllegalStateException(
"Cannot process payment in state: " + state
);
}
}
}
Для работы с коллекциями и массивами:
public void accessElement(List<String> list, int index) {
if (index < 0 || index >= list.size()) {
// IndexOutOfBoundsException - неправильный индекс
throw new IndexOutOfBoundsException(
"Index: " + index + ", Size: " + list.size()
);
}
// ...
}
Для операций, которые не поддерживаются:
public class ReadOnlyList<E> extends AbstractList<E> {
@Override
public E set(int index, E element) {
// UnsupportedOperationException - операция не поддерживается
throw new UnsupportedOperationException("This list is read-only");
}
}
Checked Exceptions - когда использовать?
// Используй Checked для ошибок, которые НУЖНО обработать
public class FileProcessor {
// IOException - known issue, клиент ДО ЛЖЕ его обработать
public void processFile(String path) throws IOException {
try (FileReader reader = new FileReader(path)) {
// read file
}
// Если файла нет - IOException обязательно обработаем выше
}
}
// Используй Checked для ошибок внешних систем
public class DatabaseService {
// SQLException - обязательно нужно обработать
public User getUserById(Long id) throws SQLException {
try (Connection conn = getConnection()) {
// execute query
}
}
}
Custom Exception - Best Practices
// ✅ Хорошо: наследуем RuntimeException для unchecked
public class ProductNotFoundException extends RuntimeException {
private final String productCode;
public ProductNotFoundException(String productCode) {
super("Product not found: " + productCode);
this.productCode = productCode;
}
public String getProductCode() {
return productCode;
}
}
// Используем:
public Product findProduct(String code) {
return productRepository.findByCode(code)
.orElseThrow(() -> new ProductNotFoundException(code));
}
// ✅ Если нужна обработка - наследуем от Exception
public class PaymentFailedException extends Exception {
private final PaymentStatus status;
private final BigDecimal amount;
public PaymentFailedException(PaymentStatus status, BigDecimal amount) {
super("Payment failed with status: " + status);
this.status = status;
this.amount = amount;
}
public PaymentStatus getStatus() {
return status;
}
public BigDecimal getAmount() {
return amount;
}
}
Praktical Guide - Таблица решений
| Ситуация | Исключение | Пример |
|---|---|---|
| Аргумент null или некорректен | IllegalArgumentException | throw new IllegalArgumentException("Email is invalid"); |
| Объект в неправильном состоянии | IllegalStateException | throw new IllegalStateException("Connection closed"); |
| Индекс вне границ | IndexOutOfBoundsException | автоматически при list.get(999) |
| Операция не поддерживается | UnsupportedOperationException | throw new UnsupportedOperationException(); |
| Файл не найден | FileNotFoundException | new FileReader("missing.txt") throws |
| БД ошибка | SQLException | ловим из JDBC |
| Парсинг JSON/XML провалился | ParseException / JsonSyntaxException | создаём свой custom exception |
| Ресурс не найден (service layer) | NotFoundException (custom) | наследуем RuntimeException |
| Конфликт данных | ConflictException (custom) | наследуем RuntimeException |
| Бизнес-правило нарушено | BusinessException (custom) | наследуем RuntimeException или Exception |
Вывод
Правило большого пальца:
- Валидация параметров →
IllegalArgumentException - Состояние объекта →
IllegalStateException - Специфичные бизнес-ошибки → создай свой
RuntimeException - Ошибки, которые нужно обработать → checked
Exception - Не используй generic
ExceptionилиThrowable