Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Исключения категории Error в Java
Error — это класс, который представляет серьёзные проблемы, которые приложение обычно НЕ должно пытаться обработать. Это критические ошибки виртуальной машины Java (JVM) и системы. В отличие от Exception, Error не рекомендуется ловить и обрабатывать — это прерогатива JVM.
Иерархия исключений в Java
Throwable
├── Error (серьёзные ошибки JVM)
│ ├── VirtualMachineError
│ │ ├── StackOverflowError
│ │ ├── OutOfMemoryError
│ │ └── UnknownError
│ ├── LinkageError
│ │ ├── ClassNotFoundException
│ │ ├── NoClassDefFoundError
│ │ └── ClassFormatError
│ ├── AssertionError
│ └── ThreadDeath
└── Exception (обрабатываемые исключения)
├── RuntimeException (unchecked)
└── ... (checked exceptions)
Основные Error в Java
1. OutOfMemoryError
Что это: JVM не может выделить память для нового объекта
// ❌ Приводит к OutOfMemoryError
List<byte[]> list = new ArrayList<>();
while (true) {
list.add(new byte[1024 * 1024]); // Добавляем по 1MB
// В итоге память заканчивается
}
// Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
Варианты OutOfMemoryError:
- Java heap space — недостаточно памяти в heap
- GC overhead limit exceeded — сборщик мусора потратил > 98% времени
- PermGen space (Java 7) — недостаточно памяти для класс-метаданных
- Metaspace (Java 8+) — переполнение Metaspace
- Direct buffer memory — переполнение DirectByteBuffer
// Нельзя обработать OutOfMemoryError:
List<byte[]> list = new ArrayList<>();
try {
while (true) {
list.add(new byte[1024 * 1024]);
}
} catch (OutOfMemoryError e) {
// ❌ К этому моменту памяти нет - ловля неэффективна
System.out.println("Out of memory");
// Приложение всё равно упадёт
}
2. StackOverflowError
Что это: стек вызовов переполнен (обычно из-за бесконечной рекурсии)
// ❌ Бесконечная рекурсия
int recursiveMethod(int n) {
return recursiveMethod(n + 1); // Вызывает себя без выхода
}
recursiveMethod(0);
// Exception in thread "main" java.lang.StackOverflowError
Почему это Error, а не Exception:
- Стек уже заполнен — невозможно создать новый Exception
- Это системная ошибка, а не ошибка логики
// Правильная рекурсия (с базовым случаем)
int factorial(int n) {
if (n <= 1) return 1; // Базовый случай - выход
return n * factorial(n - 1);
}
factorial(5); // ✓ Работает
3. NoClassDefFoundError
Что это: класс был найден при компиляции, но не найден во время выполнения
// ❌ Класс скомпилирован, но jar удалён
public class Main {
public void test() {
SomeClass obj = new SomeClass(); // Компилируется
}
}
// Если SomeClass.class нет в classpath при запуске:
// Exception in thread "main" java.lang.NoClassDefFoundError: SomeClass
Отличие от ClassNotFoundException:
// ClassNotFoundException - проверяемое исключение
try {
Class.forName("com.example.SomeClass"); // Динамическая загрузка
} catch (ClassNotFoundException e) {
// ✓ Это Exception, можно обработать
System.out.println("Class not found");
}
// NoClassDefFoundError - ошибка JVM
new SomeClass(); // Если класса нет - NoClassDefFoundError
4. ClassFormatError
Что это: файл .class имеет неверный формат
// ❌ Повреждённый class файл
try {
ClassLoader.getSystemClassLoader().loadClass("BadClass");
} catch (ClassFormatError e) {
// Неправильная структура class файла
}
5. LinkageError
Что это: ошибка при связывании (linking) классов
Подвиды:
- UnsatisfiedLinkError — native метод не найден
- IncompatibleClassChangeError — несовместимость класса (например, интерфейс изменился)
// UnsatisfiedLinkError
public class NativeExample {
native void someNativeMethod(); // Реализация в C/C++
public void test() {
someNativeMethod(); // Если native библиотека не загружена
// java.lang.UnsatisfiedLinkError: someNativeMethod
}
}
6. AssertionError
Что это: не выполнено условие в assert
public class AssertExample {
public static void main(String[] args) {
int value = 5;
assert value > 10 : "Value must be > 10"; // ❌ Условие ложно
// Exception in thread "main" java.lang.AssertionError: Value must be > 10
}
}
// Запуск с включением assert:
// java -ea AssertExample
Когда использовать assert:
public class Calculator {
public int divide(int a, int b) {
// ✓ Проверка инвариантов в private методах
assert b != 0 : "Divisor cannot be zero";
return a / b;
}
}
7. ThreadDeath
Что это: поток был остановлен методом stop() (deprecated)
// ❌ Deprecated и опасно
Thread thread = new Thread(() -> {
while (true) {
// ...
}
});
thread.start();
thread.stop(); // Генерирует ThreadDeath - никогда не используй!
Правильный способ остановить поток:
// ✓ Используй флаг
volatile boolean running = true;
Thread thread = new Thread(() -> {
while (running) {
// работа
}
});
running = false; // Мягкая остановка
8. ExceptionInInitializerError
Что это: исключение при инициализации класса
public class BadInitializer {
static {
int x = 1 / 0; // ❌ Ошибка в static блоке
// Exception in thread "main" java.lang.ExceptionInInitializerError
}
}
Почему Error — это не Exception?
| Аспект | Error | Exception |
|---|---|---|
| Причина | Ошибка JVM/системы | Ошибка приложения |
| Обработка | НЕ рекомендуется ловить | Можно и нужно ловить |
| Восстановление | Невозможно | Возможно |
| Примеры | OOM, StackOverflow | IOException, NPE |
Правило обработки Error
// ❌ НЕ ДЕЛАЙ ТАК
try {
// код
} catch (Error e) {
// Ловля Error нарушает контракт
System.out.println("Ошибка");
}
// ❌ НЕ ДЕЛАЙ И ТАК
try {
// код
} catch (Throwable t) {
// Ловишь и Exception И Error
// Это скрывает серьёзные проблемы
}
// ✅ ПРАВИЛЬНО
try {
// код
} catch (IOException e) {
// Ловишь только конкретные Exception
log.error("IO failed", e);
// Можешь что-то сделать
}
Диагностика Error
# Для OutOfMemoryError:
java -Xmx512m MyApplication
# Увеличиваем максимум памяти
# Для анализа heap dump:
jmap -dump:live,format=b,file=heap.hprof <pid>
jhat heap.hprof
# Для StackOverflowError:
java -Xss1m MyApplication
# Увеличиваем размер stack
Вывод: Error — это ошибки JVM, которые указывают на критические проблемы системы. Приложение не должно их ловить, а должно завершиться корректно. Перед запуском нужно учитывать требования к памяти и ресурсам.