Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Иерархия исключений в Java
Исключения в Java образуют иерархию классов, начинающуюся с Throwable. Правильное понимание этой иерархии критично для правильной обработки ошибок и написания robust кода.
Корень иерархии: Throwable
Все ошибки и исключения наследуются от Throwable:
public class Throwable implements Serializable {
// Основные методы
public String getMessage();
public void printStackTrace();
public StackTraceElement[] getStackTrace();
public Throwable getCause();
public synchronized Throwable initCause(Throwable cause);
public String toString();
}
// Иерархия:
// Throwable
// ├── Error (не ловим!)
// │ ├── OutOfMemoryError
// │ ├── StackOverflowError
// │ ├── VirtualMachineError
// │ └── LinkageError
// └── Exception (ловим)
// ├── Checked Exception
// │ ├── IOException
// │ ├── SQLException
// │ ├── ParseException
// │ └── ...
// └── RuntimeException (Unchecked)
// ├── NullPointerException
// ├── ArrayIndexOutOfBoundsException
// ├── IllegalArgumentException
// ├── ArithmeticException
// └── ...
1. Error — Критические ошибки JVM
Error — проблемы, которые приложение НЕ может обработать. Это проблемы JVM, а не приложения.
// OutOfMemoryError — нет памяти
public class MemoryTest {
public static void main(String[] args) {
List<byte[]> list = new ArrayList<>();
while (true) {
list.add(new byte[1024 * 1024]); // 1MB
// java.lang.OutOfMemoryError: Java heap space
}
}
}
// StackOverflowError — переполнение стека
public class RecursionTest {
public void recursive() {
recursive(); // Бесконечная рекурсия
// java.lang.StackOverflowError
}
}
// VirtualMachineError — ошибка JVM
// LinkageError — ошибка загрузки класса
// ❌ НЕ ловим Error!
try {
// что-то
} catch (Error e) { // Плохая практика
// Это скроет критичные ошибки
}
// ✅ Только для очень специфичных случаев
try {
// что-то
} catch (OutOfMemoryError e) {
// Может быть graceful shutdown
System.err.println("Out of memory, shutting down");
System.exit(1);
}
2. Exception — Обрабатываемые исключения
2.1 Checked Exception
Checked Exception — компилятор ТРЕБУЕТ обработать или пробросить. Наследуют Exception, но не RuntimeException.
// IOException — checked exception
public class FileReader {
// Вариант 1: Обработать
public String readFile(String path) {
try {
Files.readString(Paths.get(path));
} catch (IOException e) {
System.err.println("Cannot read file: " + e.getMessage());
return "";
}
}
// Вариант 2: Пробросить
public String readFile(String path) throws IOException {
return Files.readString(Paths.get(path)); // Компилятор доволен
}
}
// SQLException — checked exception
public class DatabaseService {
public User getUserById(Long id) throws SQLException {
Connection conn = getConnection();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM users WHERE id = " + id);
// IOException, SQLException ДОЛЖНЫ быть обработаны или пробросены
}
}
// ParseException, ClassNotFoundException, FileNotFoundException
public class ConfigLoader {
public void loadConfig(String path) throws IOException, ParseException {
String json = Files.readString(Paths.get(path)); // IOException
JSONObject obj = new JSONObject(json); // ParseException
}
}
// Custom checked exception
public class PaymentFailedException extends Exception {
public PaymentFailedException(String message) {
super(message);
}
public PaymentFailedException(String message, Throwable cause) {
super(message, cause);
}
}
public class PaymentService {
public void processPayment(Order order) throws PaymentFailedException {
try {
// Вызов платежного API
if (paymentAPI.charge(order.getAmount()) == null) {
throw new PaymentFailedException(
"Payment gateway returned null response"
);
}
} catch (HttpException e) {
throw new PaymentFailedException(
"Payment service unavailable", e
);
}
}
}
Когда использовать Checked Exception:
- Predictable, recoverable ошибки
- IOException (файл может быть переместен)
- SQLException (БД может быть недоступна)
- Но НЕ для всех случаев (смотри ниже)
2.2 Unchecked Exception (RuntimeException)
RuntimeException — не требует обработки в throws. Наследуют RuntimeException. Используются для программных ошибок.
// NullPointerException
public class NullPointerExample {
public void process(User user) {
String name = user.getName(); // NPE если user == null
// Нет необходимости в throws NullPointerException
}
}
// ArrayIndexOutOfBoundsException
public class ArrayExample {
public void access(int[] arr, int index) {
int value = arr[index]; // ArrayIndexOutOfBoundsException если index >= arr.length
// Не нужно в throws
}
}
// IllegalArgumentException
public class ValidationService {
public void setAge(int age) {
if (age < 0 || age > 150) {
throw new IllegalArgumentException(
"Age must be between 0 and 150, got: " + age
);
}
this.age = age;
}
}
// ArithmeticException
public class Calculator {
public int divide(int a, int b) {
return a / b; // ArithmeticException при b = 0
}
}
// ClassCastException
public class TypeConversion {
public void process(Object obj) {
String str = (String) obj; // CCE если obj не String
}
}
// IndexOutOfBoundsException
public class ListAccess {
public void access(List<String> list, int index) {
String item = list.get(index); // IndexOutOfBoundsException
}
}
// Custom unchecked exception
public class BusinessRuleViolation extends RuntimeException {
public BusinessRuleViolation(String message) {
super(message);
}
}
public class OrderService {
public void createOrder(Order order) {
if (order.getAmount() < 10) {
throw new BusinessRuleViolation(
"Minimum order amount is 10"
); // Не нужен throws
}
// создание заказа
}
}
Правильная обработка исключений
// Хорошая иерархия обработки (от специфичного к общему)
public void process() {
try {
riskyOperation();
} catch (SpecificException e) {
// Самая специфичная обработка
handleSpecific(e);
} catch (IOException e) {
// Более общая
handleIO(e);
} catch (Exception e) {
// Самая общая
handleGeneral(e);
} finally {
// Всегда выполняется
cleanup();
}
}
// Правильное логирование
try {
someMethod();
} catch (IOException e) {
logger.error("Failed to read file", e); // Пробросить stack trace
// ❌ Плохо:
// logger.error(e.toString()); // Потеряется stack trace
// System.out.println(e); // Не логируется
}
// Try-with-resources
try (InputStream is = new FileInputStream("file.txt")) {
byte[] data = is.readAllBytes();
// Автоматически закроется даже при исключении
} catch (IOException e) {
logger.error("Cannot read file", e);
}
// Явное преобразование исключения
public class RepositoryService {
public User getUserById(Long id) {
try {
return queryDatabase(id);
} catch (SQLException e) {
// Преобразуем checked -> unchecked
throw new DataAccessException(
"Cannot fetch user: " + id, e
); // Пробросить с cause
}
}
}
// Цепь исключений (exception chaining)
try {
// что-то
} catch (IOException e) {
throw new ApplicationException(
"Failed to process request",
e // Сохраняем исходное исключение как cause
);
}
Сравнение Checked vs Unchecked
| Аспект | Checked | Unchecked |
|---|---|---|
| Наследует | Exception (не Runtime) | RuntimeException |
| Обработка | ОБЯЗАТЕЛЬНА (throws/try-catch) | ОПЦИОНАЛЬНА |
| Когда | Predictable errors | Programming errors |
| Примеры | IOException, SQLException | NullPointerException |
| Декларация | public void method() throws IOException | не нужна |
Best Practices
- Не ловка generic Exception:
// ❌ Плохо
try {
code();
} catch (Exception e) { // Слишком широко
e.printStackTrace();
}
// ✅ Хорошо
try {
code();
} catch (SpecificException e) {
handleSpecific(e);
} catch (IOException e) {
handleIO(e);
}
- Пробрасывай с информацией:
// ❌ Плохо
throw new RuntimeException("Error");
// ✅ Хорошо
throw new RuntimeException(
"Cannot process order " + orderId + ": invalid amount",
originalException
);
- Используй custom exceptions:
public class InvalidUserException extends RuntimeException {
private final Long userId;
public InvalidUserException(Long userId) {
super("User not found: " + userId);
this.userId = userId;
}
public Long getUserId() {
return userId;
}
}
Правильная иерархия и обработка исключений — основа надежного и поддерживаемого кода.