Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Обработка ошибок в Java
Обработка ошибок - один из самых критичных аспектов разработки надежного программного обеспечения. Java предоставляет мощный механизм через исключения.
Иерархия исключений в Java
Throwable
├── Error (не обрабатываем обычно)
│ ├── OutOfMemoryError
│ ├── StackOverflowError
│ └── VirtualMachineError
└── Exception
├── Checked Exception (обязательно обрабатывать)
│ ├── IOException
│ ├── SQLException
│ └── FileNotFoundException
└── Unchecked Exception (необязательно обрабатывать)
├── RuntimeException
│ ├── NullPointerException
│ ├── IllegalArgumentException
│ └── IndexOutOfBoundsException
└── ...
1. Try-Catch блоки
Базовый способ обработки исключений:
try {
// Код, который может выбросить исключение
int result = 10 / 0;
} catch (ArithmeticException e) {
// Обработка исключения
System.err.println("Ошибка деления: " + e.getMessage());
} finally {
// Код, который выполнится в любом случае
System.out.println("Блок finally всегда выполняется");
}
2. Множественные catch блоки
try {
processFile("data.txt");
} catch (FileNotFoundException e) {
System.err.println("Файл не найден: " + e.getMessage());
} catch (IOException e) {
System.err.println("Ошибка ввода-вывода: " + e.getMessage());
} catch (Exception e) {
System.err.println("Неожиданная ошибка: " + e.getMessage());
e.printStackTrace();
}
3. Multi-catch (Java 7+)
Обработка нескольких типов исключений одним блоком:
try {
// Код
readData();
} catch (IOException | SQLException e) {
// Обработка нескольких типов
logger.error("Database or I/O error", e);
} catch (Exception e) {
logger.error("Unexpected error", e);
}
4. Try-with-resources (Java 7+)
Автоматическое закрытие ресурсов:
// ❌ Плохо - нужно вручную закрывать
FileReader reader = new FileReader("file.txt");
try {
int data = reader.read();
} finally {
reader.close(); // Может выбросить исключение!
}
// ✅ Хорошо - автоматическое управление
try (FileReader reader = new FileReader("file.txt")) {
int data = reader.read();
System.out.println(data);
} catch (IOException e) {
System.err.println("IO Error: " + e.getMessage());
}
5. Выброс исключений
public void validateAge(int age) throws IllegalArgumentException {
if (age < 0 || age > 150) {
throw new IllegalArgumentException("Invalid age: " + age);
}
}
// С кастомным исключением
public class InsufficientFundsException extends Exception {
private double requiredAmount;
public InsufficientFundsException(String message, double requiredAmount) {
super(message);
this.requiredAmount = requiredAmount;
}
public double getRequiredAmount() {
return requiredAmount;
}
}
public void withdraw(double amount) throws InsufficientFundsException {
if (amount > balance) {
throw new InsufficientFundsException(
"Insufficient funds",
amount - balance
);
}
balance -= amount;
}
6. Цепочка исключений (Exception Chaining)
Сохраняем оригинальное исключение для отладки:
try {
connectToDatabase();
} catch (SQLException e) {
// Оборачиваем в более высокоуровневое исключение
throw new DataAccessException(
"Failed to load user data",
e // Сохраняем cause
);
}
// Или используем initCause
catch (SQLException e) {
DataAccessException ex = new DataAccessException("DB error");
ex.initCause(e);
throw ex;
}
7. Custom исключения
// Checked Exception - для ожидаемых ошибок
public class PaymentFailedException extends Exception {
private String paymentId;
public PaymentFailedException(String message, String paymentId) {
super(message);
this.paymentId = paymentId;
}
public String getPaymentId() {
return paymentId;
}
}
// Unchecked Exception - для логических ошибок
public class InvalidOrderException extends RuntimeException {
public InvalidOrderException(String message) {
super(message);
}
}
8. Логирование ошибок
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class UserService {
private static final Logger logger = LoggerFactory.getLogger(UserService.class);
public void createUser(User user) {
try {
validateUser(user);
saveUser(user);
logger.info("User created: {}", user.getId());
} catch (IllegalArgumentException e) {
logger.warn("Invalid user data: {}", e.getMessage());
throw e;
} catch (Exception e) {
logger.error("Failed to create user", e);
throw new RuntimeException("User creation failed", e);
}
}
}
9. Лучшие практики
// ❌ Плохо - игнорирование исключения
try {
riskyOperation();
} catch (Exception e) {
// Молчаливая ошибка - опасно!
}
// ❌ Плохо - слишком общий catch
try {
// Много кода
} catch (Exception e) {
e.printStackTrace();
}
// ✅ Хорошо - специфичные исключения
try {
fileOperation();
} catch (FileNotFoundException e) {
logger.error("File not found: {}", fileName);
return defaultValue();
} catch (IOException e) {
logger.error("IO error: {}", e.getMessage(), e);
throw new DataAccessException("Failed to read file", e);
}
// ✅ Хорошо - проверка перед операцией
if (user != null) {
user.getName(); // Безопаснее, чем обработка NullPointerException
}
// ✅ Хорошо - валидация на входе
public void setAge(int age) {
if (age < 0) {
throw new IllegalArgumentException("Age cannot be negative");
}
this.age = age;
}
10. Обработка ошибок в потоках
// Неправильно - исключение в потоке теряется
ExecutorService executor = Executors.newFixedThreadPool(1);
executor.submit(() -> {
throw new RuntimeException("Error in thread");
});
// Правильно - использу Future
Future<?> future = executor.submit(() -> {
throw new RuntimeException("Error in thread");
});
try {
future.get(); // Выбросит исключение
} catch (ExecutionException e) {
logger.error("Task failed", e.getCause());
}
// Или используй UncaughtExceptionHandler
Thread.setDefaultUncaughtExceptionHandler((thread, throwable) -> {
logger.error("Uncaught exception in thread", throwable);
});
Вывод: обработка ошибок требует баланса между специфичностью и практичностью. Используйте checked исключения для ожидаемых ошибок, логируйте все проблемы, не скрывайте исключения и сохраняйте информацию о причинах ошибок для отладки.