Что находится в вершине иерархии исключений?
В самом верху иерархии всех объектов, которые можно выбросить и перехватить, находится класс java.lang.Throwable.
Junior Level
Корень иерархии — java.lang.Throwable
В самом верху иерархии всех объектов, которые можно выбросить и перехватить, находится класс java.lang.Throwable.
Object
└── Throwable
├── Error (фатальные ошибки JVM)
│ ├── OutOfMemoryError
│ ├── StackOverflowError
│ └── NoClassDefFoundError
│
└── Exception (ошибки приложения)
├── RuntimeException (unchecked)
│ ├── NullPointerException
│ └── IllegalArgumentException
│
└── Checked Exceptions
├── IOException
└── SQLException
Две основные ветви
Error — фатальные проблемы JVM:
OutOfMemoryError— закончилась памятьStackOverflowError— бесконечная рекурсия- Ловить не нужно — система в нестабильном состоянии
Exception — ошибки приложения:
- Можно и нужно обрабатывать
- Делятся на checked и unchecked
Error – проблемы, которые приложение не может исправить (память, стек). Exception – проблемы, которые может. Разделение в иерархии позволяет ловить Exception, не ловя Error.
Пример
// Throwable — родитель всех исключений
try {
// какой-то код
} catch (Throwable t) {
// Перехватит ВСЁ, включая Error (обычно так не делают)
System.err.println("Caught: " + t.getMessage());
}
Middle Level
Почему Throwable реализует Serializable?
Сериализация – превращение объекта в байты для передачи по сети или сохранения. Это нужно для RMI (удалённых вызовов), JMX, кеширования. Исключение должно быть сериализуемо, чтобы «путешествовать» между JVM.
Это критично для распределённых систем (RMI, JMX). Когда исключение происходит на сервере, JVM сериализует его вместе со стек-трейсом и передаёт клиенту.
Ключевые подклассы Error
OutOfMemoryError— разные подтипы:Java heap space— закончилась кучаMetaspace— закончилась память под метаданные классовUnable to create new native thread— ОС запретила потоки
-
ThreadDeath— выбрасывается приThread.stop()(deprecated). ЭтоError, чтобы обычныйcatch (Exception e)не проглотил его. NoClassDefFoundError— класс был при компиляции, но пропал в рантайме. Нарушена целостность среды.
Проблема проброса через ExecutorService
Когда исключение происходит внутри потока в пуле, оно перехватывается ExecutorService и сохраняется внутри Future:
Future<?> future = executor.submit(() -> {
throw new RuntimeException("Task failed!");
});
// Исключение "спрятано" внутри Future
try {
future.get(); // Здесь вылетит ExecutionException
} catch (ExecutionException e) {
System.err.println("Cause: " + e.getCause()); // RuntimeException
}
// ExecutorService перехватывает все исключения из задач и сохраняет их внутри Future.
// При вызове future.get() exception оборачивается в ExecutionException.
// Чтобы добраться до причины: e.getCause().
fillInStackTrace()
fillInStackTrace() – нативный метод (написан на C/C++, не на Java). Обходит стек вызовов на уровне ОС, создавая снимок всех кадров. Это дорого: требует перехода между Java и нативным кодом + обход всего стека.
При вызове getStackTrace() нативная структура преобразуется в массив StackTraceElement[] — это ленивая оптимизация, но заполнение нативной структуры всё равно дорогое.
Senior Level
Under the Hood: скрытое поле backtrace
Внутри Throwable есть поле private Object backtrace, заполняемое нативным методом fillInStackTrace(). Оно хранит ссылку на нативный стек вызовов в памяти JVM.
Serialization Pitfall: при сериализации нативный backtrace теряется, и JVM конвертирует его в массив Java-объектов. Это увеличивает размер пакета и нагрузку на CPU.
Отключение стек-трейса для производительности
public class FastException extends RuntimeException {
public FastException(String message) {
// enableSuppression = true, writableStackTrace = false
super(message, null, true, false);
}
}
Ускоряет создание в десятки раз — нативный обход стека не выполняется.
Immutable Exceptions
В высоконагруженных системах создают статические инстансы:
public static final MyException INVALID_DATA =
new MyException("Invalid data", null, true, false);
Не создаёт новые объекты, но в логах будет одинаковый стек-трейс.
Suppressed Exceptions
Введены в Java 7 для try-with-resources. Если исключение возникло в try, а второе — при закрытии ресурса в finally, первое становится основным, второе добавляется в suppressed:
try {
resource.doWork(); // IOException #1
} finally {
resource.close(); // IOException #2
}
// IOException #1 — основное, #2 — suppressed
Диагностика
- Никогда не делайте
catch (Throwable t)в бизнес-логике — перехватитOutOfMemoryError - Root Cause Analysis — используйте
ExceptionUtils.getRootCause()для поиска первопричины - Распределённые системы — на границе сервиса извлекайте сообщение и код ошибки, передавайте только DTO
🎯 Шпаргалка для интервью
Обязательно знать:
- Корень иерархии —
java.lang.Throwable(неException) - Две ветви:
Error(фатальные проблемы JVM) иException(ошибки приложения) - Error —
OutOfMemoryError,StackOverflowError,NoClassDefFoundError— не ловить - Exception делится на
RuntimeException(unchecked) и checked exceptions fillInStackTrace()— нативный метод, обходит стек вызовов, дорогая операция- Suppressed exceptions — механизм Java 7 для try-with-resources (сохраняет второе исключение)
- Отключение стек-трейсa (
writableStackTrace = false) ускоряет создание в десятки раз - При сериализации нативный
backtraceтеряется — конвертируется в Java-объекты
Частые уточняющие вопросы:
- Почему Throwable реализует Serializable? — Для RMI, JMX, кеширования — исключения «путешествуют» между JVM
- Что будет, если перехватить OutOfMemoryError? — JVM может быть в нестабильном состоянии, следующая операция упадёт
- Что такое suppressed exceptions? — Когда в try и close() упали два исключения, второе добавляется в suppressed-список первого
- Почему нельзя создавать immutable исключения для всего? — Одинаковый стек-трейс затрудняет отладку
Красные флаги (НЕ говорить):
- “Корень иерархии — Exception” — нет, Throwable
- “Я ловлю Throwable в бизнес-логике для надёжности” — это перехватит OutOfMemoryError
- “fillInStackTrace() — обычный Java-метод” — нет, нативный, обходит стек на уровне ОС
Связанные темы:
- [[Что такое Throwable]]
- [[В чём разница между Error и Exception]]
- [[Что такое suppressed exceptions]]
- [[Что такое stack trace]]
- [[Что такое try-with-resources]]