← Назад к вопросам
Что такое Java Exceptions?
2.0 Middle🔥 181 комментариев
#SOLID и паттерны проектирования#Spring Boot и Spring Data
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Java Exceptions: механизм обработки ошибок
Java Exceptions — это объектно-ориентированный механизм для обработки ошибок и исключительных ситуаций. В отличие от других языков (например, C), которые возвращают error codes, Java использует exceptions для сигнализации об ошибках и их обработки в специальных catch блоках.
Иерархия Exceptions в Java
Throwable
/ \
Error Exception
/ | \ / \
... OutOfMemory ... IOException RuntimeException
| | / | \
| | NullPointerException ...
| | ArrayIndexOutOfBoundsException
| | ClassCastException
FileNotFoundException
Три типа Throwables:
-
Error — серьёзные проблемы, которые приложение обычно не может обработать
- OutOfMemoryError
- StackOverflowError
- VirtualMachineError
-
Checked Exceptions (extends Exception, но не RuntimeException)
- IOException, SQLException, ClassNotFoundException
- Компилятор ЗАСТАВЛЯЕТ их обработать
-
Unchecked Exceptions / Runtime Exceptions (extends RuntimeException)
- NullPointerException, ArrayIndexOutOfBoundsException
- Не обязательно обрабатывать (но можно)
Try-Catch-Finally блоки
public class ExceptionHandling {
public static void main(String[] args) {
try {
// Код, который может выбросить exception
int result = 10 / 0; // ArithmeticException
} catch (ArithmeticException e) {
// Обработка конкретного exception
System.out.println("Ошибка: деление на ноль!");
System.out.println("Message: " + e.getMessage());
} catch (Exception e) {
// Можно ловить несколько exceptions
System.out.println("Неизвестная ошибка");
} finally {
// Выполняется ВСЕГДА (даже если был exception)
System.out.println("Cleanup операции");
}
}
}
Checked vs Unchecked Exceptions
Checked Exception (обязательна обработка)
// Компилятор ТРЕБУЕТ обработку IOException
public void readFile(String path) throws IOException {
FileInputStream fis = new FileInputStream(path);
// ❌ ОШИБКА: IOException не обработан!
// Нужно либо catch, либо throws
}
// ✅ Правильно: с catch
public void readFile(String path) {
try {
FileInputStream fis = new FileInputStream(path);
} catch (IOException e) {
System.out.println("File not found: " + e.getMessage());
}
}
// ✅ Правильно: с throws
public void readFile(String path) throws IOException {
FileInputStream fis = new FileInputStream(path);
// IOException пойдет выше в call stack
}
Unchecked Exception (опциональна обработка)
// RuntimeException — не нужно обрабатывать
public int divide(int a, int b) {
return a / b; // Может выбросить ArithmeticException, но это OK
}
// Если хотим обработать
public int divide(int a, int b) {
try {
return a / b;
} catch (ArithmeticException e) {
return 0; // default value
}
}
Создание Custom Exceptions
// Custom Exception для бизнес-логики
public class InsufficientFundsException extends Exception {
private double requiredAmount;
private double availableAmount;
public InsufficientFundsException(double required, double available) {
super("Insufficient funds: required " + required + ", available " + available);
this.requiredAmount = required;
this.availableAmount = available;
}
public double getShortfall() {
return requiredAmount - availableAmount;
}
}
public class BankAccount {
private double balance;
public void withdraw(double amount) throws InsufficientFundsException {
if (amount > balance) {
throw new InsufficientFundsException(amount, balance);
}
balance -= amount;
}
}
// Использование
public static void main(String[] args) {
BankAccount account = new BankAccount();
try {
account.withdraw(1000); // будет exception
} catch (InsufficientFundsException e) {
System.out.println("Error: " + e.getMessage());
System.out.println("Shortfall: " + e.getShortfall());
}
}
Exception Chaining (Цепочка исключений)
Когда нужно обернуть одно exception в другое:
public void saveToDatabase(String data) throws DataAccessException {
try {
// SQL операция
jdbcTemplate.update("INSERT INTO ...", data);
} catch (SQLException e) {
// Оборачиваем SQLException (checked) в DataAccessException (unchecked)
throw new DataAccessException("Failed to save data", e);
// cause = e (оригинальная ошибка сохраняется)
}
}
// Обработка
try {
saveToDatabase("some data");
} catch (DataAccessException e) {
System.out.println("Error: " + e.getMessage());
System.out.println("Cause: " + e.getCause().getMessage());
}
Try-with-resources (автоматическое закрытие ресурсов)
// ❌ Старый способ — нужно закрывать вручную
public void readFile(String path) throws IOException {
FileInputStream fis = new FileInputStream(path);
try {
byte[] data = new byte[1024];
fis.read(data);
} finally {
fis.close(); // не забыть!
}
}
// ✅ Try-with-resources — автоматически закроет
public void readFile(String path) throws IOException {
try (FileInputStream fis = new FileInputStream(path)) {
byte[] data = new byte[1024];
fis.read(data);
}
// fis.close() вызовется автоматически!
}
Multi-catch (Java 7+)
// ❌ Старый способ
try {
// операции
} catch (FileNotFoundException e) {
handleError(e);
} catch (SecurityException e) {
handleError(e);
} catch (IOException e) {
handleError(e);
}
// ✅ Современный способ
try {
// операции
} catch (FileNotFoundException | SecurityException | IOException e) {
handleError(e);
}
Exception Handling Best Practices
1. Ловить конкретные exceptions, не Exception
// ❌ Плохо — ловишь ВСЕ exceptions
try {
someMethod();
} catch (Exception e) {
// Могла быть ошибка, которую не ожидаешь
log.error("Something happened");
}
// ✅ Хорошо — ловишь конкретные
try {
someMethod();
} catch (IOException e) {
log.error("File operation failed", e);
} catch (DatabaseException e) {
log.error("Database error", e);
}
2. Логировать exception с контекстом
// ❌ Плохо
catch (SQLException e) {
System.out.println("Error");
}
// ✅ Хорошо
catch (SQLException e) {
log.error("Failed to execute query for user: " + userId, e);
// e = full stack trace + message
}
3. Не игнорировать exceptions
// ❌ Очень плохо — молча проглотить ошибку
try {
riskyOperation();
} catch (Exception e) {
// ничего не делаем
}
// ✅ Если точно нужно игнорировать
try {
riskyOperation();
} catch (SpecificException e) {
// это нормально, игнорируем
log.debug("Expected error: " + e.getMessage());
}
4. Пробрасывать выше, если не можешь обработать
// ❌ Плохо — обрабатываем, но не можем сделать ничего
public void processPayment(Order order) {
try {
paymentGateway.charge(order.getTotal());
} catch (PaymentException e) {
// что делать? Не знаем
log.error("Payment failed", e);
}
}
// ✅ Хорошо — пробрасываем выше
public void processPayment(Order order) throws PaymentException {
paymentGateway.charge(order.getTotal());
// Контроллер решит, что делать (refund, retry и т.д.)
}
Exception Handling в REST API
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(InsufficientFundsException.class)
public ResponseEntity<ErrorResponse> handleInsufficientFunds(
InsufficientFundsException e) {
return ResponseEntity
.status(HttpStatus.BAD_REQUEST)
.body(new ErrorResponse(
"INSUFFICIENT_FUNDS",
e.getMessage()
));
}
@ExceptionHandler(EntityNotFoundException.class)
public ResponseEntity<ErrorResponse> handleNotFound(
EntityNotFoundException e) {
return ResponseEntity
.status(HttpStatus.NOT_FOUND)
.body(new ErrorResponse(
"NOT_FOUND",
e.getMessage()
));
}
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleGenericException(
Exception e) {
return ResponseEntity
.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ErrorResponse(
"INTERNAL_ERROR",
"An unexpected error occurred"
));
}
}
public class ErrorResponse {
private String code;
private String message;
public ErrorResponse(String code, String message) {
this.code = code;
this.message = message;
}
}
Проверка Stack Trace
try {
riskyOperation();
} catch (SQLException e) {
// Получить полный stack trace
e.printStackTrace(); // выведет все методы, вызвавшие друг друга
// Или в логи
log.error("SQL Error", e);
// Получить причину
Throwable cause = e.getCause();
// Получить все элементы stack
StackTraceElement[] trace = e.getStackTrace();
}
Производительность Exceptions
// ⚠️ Важно: Exceptions — дорогие!
// Создание exception = создание stack trace = медленно
// ❌ Плохо — exception в цикле
for (String item : items) {
try {
parseInteger(item); // может выбросить exception
} catch (NumberFormatException e) {
// если item не число, exception выбросится
}
}
// ✅ Хорошо — проверка перед операцией
for (String item : items) {
if (isNumeric(item)) { // проверяем без exception
parseInteger(item);
}
}
// Разница: если много не-чисел, то первый вариант x100 медленнее
Вывод
Java Exceptions — это powerful механизм для обработки ошибок:
- Checked vs Unchecked — разные подходы к обработке
- Try-catch-finally — базовая структура
- Custom exceptions — для business logic
- Best practices — ловить конкретные, логировать с контекстом
- Performance — exceptions дорогие, используй их для exceptional situations
На собеседовании важно показать, что ты:
- Понимаешь иерархию exceptions
- Знаешь разницу между checked и unchecked
- Умеешь писать custom exceptions
- Следуешь best practices в обработке ошибок