← Назад к вопросам
Какие знаешь способы обработки исключения?
1.0 Junior🔥 281 комментариев
#Основы Java
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Способы обработки исключений
Exception Handling — критическая часть надежного кода в Java. Существует несколько стратегий обработки исключений, каждая из которых применяется в зависимости от контекста и требований приложения.
1. Try-Catch блоки (Classic approach)
Базовая структура
try {
// Код, который может выбросить исключение
int result = 10 / Integer.parseInt("abc");
System.out.println("Result: " + result);
} catch (NumberFormatException e) {
// Обработка конкретного исключения
System.err.println("Invalid number format: " + e.getMessage());
} catch (ArithmeticException e) {
// Обработка другого типа исключения
System.err.println("Division by zero: " + e.getMessage());
} catch (Exception e) {
// Обработка всех остальных исключений
System.err.println("Unexpected error: " + e.getMessage());
}
Множественные catch блоки (Multi-catch)
try {
// Код, который может выбросить исключение
parseAndProcessData("data.json");
} catch (FileNotFoundException | JsonParseException e) {
// Обработка нескольких типов исключений одинаково
logger.error("Failed to process file: " + e.getMessage());
showErrorToUser("Unable to load data");
} catch (IOException e) {
logger.error("I/O error: " + e.getMessage());
}
Иерархия обработки (от специфичных к общим)
try {
database.connect();
database.query("SELECT * FROM users");
} catch (SQLSyntaxErrorException e) {
// Специфичное исключение для SQL синтаксиса
logger.error("SQL syntax error", e);
notifyDeveloper(e);
} catch (SQLException e) {
// Более общее исключение для БД
logger.error("Database error", e);
} catch (Exception e) {
// Самое общее исключение
logger.error("Unexpected error", e);
}
2. Try-Catch-Finally блоки
Finally гарантирует выполнение очистки ресурсов
Connection connection = null;
try {
connection = getConnection();
connection.setAutoCommit(false);
// Выполнение операций
updateUser(connection, user);
connection.commit();
System.out.println("User updated successfully");
} catch (SQLException e) {
logger.error("Database error", e);
if (connection != null) {
try {
connection.rollback();
} catch (SQLException rollbackEx) {
logger.error("Rollback failed", rollbackEx);
}
}
throw new DataAccessException("Failed to update user", e);
} finally {
// Выполняется ВСЕГДА, даже при исключении или return
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
logger.error("Failed to close connection", e);
}
}
}
3. Try-with-resources (Автоматическое управление ресурсами)
Рекомендуемый способ (Java 7+)
// Автоматическое закрытие ресурса
try (BufferedReader reader = new BufferedReader(new FileReader("file.txt"))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
logger.error("Failed to read file", e);
}
// reader.close() вызовется автоматически
// Несколько ресурсов
try (
Connection connection = getConnection();
PreparedStatement statement = connection.prepareStatement("SELECT * FROM users");
ResultSet resultSet = statement.executeQuery()
) {
while (resultSet.next()) {
System.out.println(resultSet.getString("name"));
}
} catch (SQLException e) {
logger.error("Database error", e);
}
// Все три ресурса закроются автоматически
// Custom AutoCloseable ресурс
public class DatabaseConnection implements AutoCloseable {
@Override
public void close() throws Exception {
// Очистка ресурсов
System.out.println("Connection closed");
}
}
// Использование
try (DatabaseConnection db = new DatabaseConnection()) {
db.execute("SELECT * FROM users");
} catch (Exception e) {
logger.error("Error", e);
}
4. Выброс исключений (Throwing Exceptions)
Пробрасывание исключения вверх
public void validateUser(User user) throws IllegalArgumentException {
if (user == null) {
throw new IllegalArgumentException("User cannot be null");
}
if (user.getName() == null || user.getName().isEmpty()) {
throw new IllegalArgumentException("User name cannot be empty");
}
}
public User getUserById(Long id) throws UserNotFoundException {
return userRepository.findById(id)
.orElseThrow(() -> new UserNotFoundException("User not found with id: " + id));
}
// Использование
try {
User user = getUserById(999L);
} catch (UserNotFoundException e) {
logger.warn("User not found", e);
return ResponseEntity.notFound().build();
}
Пробрасывание с цепочкой (Exception Chaining)
public void processData(String filePath) throws DataProcessingException {
try {
readFile(filePath);
parseData();
saveToDatabase();
} catch (IOException e) {
// Оборачиваем нижнеуровневое исключение в свое
throw new DataProcessingException("Failed to process data", e);
} catch (SQLException e) {
throw new DataProcessingException("Failed to save data to database", e);
}
}
// Использование
try {
processData("data.csv");
} catch (DataProcessingException e) {
logger.error("Data processing failed: " + e.getMessage());
logger.debug("Root cause: ", e.getCause()); // Исходное исключение
}
5. Custom исключения
// Checked исключение (наследует Exception)
public class UserNotFoundException extends Exception {
public UserNotFoundException(String message) {
super(message);
}
public UserNotFoundException(String message, Throwable cause) {
super(message, cause);
}
}
// Unchecked исключение (наследует RuntimeException) — РЕКОМЕНДУЕТСЯ
public class InsufficientFundsException extends RuntimeException {
private final BigDecimal required;
private final BigDecimal available;
public InsufficientFundsException(String message, BigDecimal required, BigDecimal available) {
super(message);
this.required = required;
this.available = available;
}
public BigDecimal getRequired() { return required; }
public BigDecimal getAvailable() { return available; }
}
// Использование
public void transfer(Account from, Account to, BigDecimal amount) {
if (from.getBalance().compareTo(amount) < 0) {
throw new InsufficientFundsException(
"Insufficient funds for transfer",
amount,
from.getBalance()
);
}
from.debit(amount);
to.credit(amount);
}
// Обработка
try {
transfer(fromAccount, toAccount, amount);
} catch (InsufficientFundsException e) {
logger.warn("Transfer failed: " + e.getMessage());
response.put("required", e.getRequired());
response.put("available", e.getAvailable());
}
6. Обработка в Spring (Global Exception Handler)
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(UserNotFoundException.class)
public ResponseEntity<ErrorResponse> handleUserNotFound(UserNotFoundException ex) {
ErrorResponse error = new ErrorResponse(
"USER_NOT_FOUND",
ex.getMessage(),
System.currentTimeMillis()
);
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);
}
@ExceptionHandler(IllegalArgumentException.class)
public ResponseEntity<ErrorResponse> handleIllegalArgument(IllegalArgumentException ex) {
ErrorResponse error = new ErrorResponse(
"INVALID_INPUT",
ex.getMessage(),
System.currentTimeMillis()
);
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error);
}
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleGenericException(Exception ex) {
logger.error("Unexpected error", ex);
ErrorResponse error = new ErrorResponse(
"INTERNAL_ERROR",
"An unexpected error occurred",
System.currentTimeMillis()
);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error);
}
}
// Контроллер
@RestController
@RequestMapping("/api/v1/users")
public class UserController {
@GetMapping("/{id}")
public ResponseEntity<UserDto> getUser(@PathVariable Long id) {
User user = userService.getUserById(id); // Может выбросить UserNotFoundException
return ResponseEntity.ok(new UserDto(user));
}
}
7. Optional для избежания исключений
// Вместо выброса исключения
public User getUserById(Long id) throws UserNotFoundException {
return userRepository.findById(id)
.orElseThrow(() -> new UserNotFoundException("User not found"));
}
// Можно вернуть Optional
public Optional<User> findUserById(Long id) {
return userRepository.findById(id);
}
// Использование
findUserById(1L)
.ifPresent(user -> System.out.println(user.getName()))
.ifPresentOrElse(
user -> processUser(user),
() -> logger.warn("User not found")
);
8. Логирование и отладка
public void processOrder(Order order) {
try {
validateOrder(order);
saveOrder(order);
notifyCustomer(order);
} catch (OrderValidationException e) {
logger.error("Order validation failed for order {}: {}", order.getId(), e.getMessage(), e);
// Отправить сообщение об ошибке пользователю
throw e;
} catch (Exception e) {
logger.error("Unexpected error processing order {}", order.getId(), e);
// Оборачиваем в свое исключение
throw new OrderProcessingException("Failed to process order", e);
}
}
9. Функциональный подход (Java 8+)
// Функция, которая может выбросить исключение
@FunctionalInterface
public interface CheckedFunction<T, R> {
R apply(T t) throws Exception;
}
// Обработка
public static <T, R> Function<T, R> unchecked(CheckedFunction<T, R> f) {
return t -> {
try {
return f.apply(t);
} catch (Exception e) {
throw new RuntimeException(e);
}
};
}
// Использование в Stream
List<Integer> numbers = Arrays.asList("1", "2", "abc", "4");
numbers.stream()
.map(unchecked(Integer::parseInt))
.forEach(System.out::println);
Best Practices
- Используй checked исключения редко — unchecked (RuntimeException) проще
- Логируй исключения — важно для отладки
- Не игнорируй исключения — пустые catch блоки опасны
- Используй try-with-resources — для управления ресурсами
- Выбрасывай специфичные исключения — помогает обработке
- Оборачивай исключения цепочкой — сохраняй контекст ошибки
- Используй Global Exception Handler в Spring — централизованная обработка
- Предпочитай Optional — где можно, вместо выброса исключений
Правильная обработка исключений — основа надежного и поддерживаемого Java приложения.