Що таке Throwable?
Throwable -- клас, а не інтерфейс, тому що зберігає стан: стек-трейс, повідомлення, причину, suppressed-список. Інтерфейс не може зберігати дані.
Junior Level
Визначення
java.lang.Throwable — це базовий клас для всіх об’єктів, які можна викинути (throw) і перехопити (catch). Без наслідування від Throwable об’єкт не можна використовувати як виняток.
Throwable – клас, а не інтерфейс, тому що зберігає стан: стек-трейс, повідомлення, причину, suppressed-список. Інтерфейс не може зберігати дані.
Ієрархія
Throwable
├── Error — фатальні помилки JVM
│ ├── OutOfMemoryError
│ └── StackOverflowError
└── Exception — помилки додатку
├── RuntimeException (unchecked)
└── Checked Exceptions
Основні методи
Throwable t = new Exception("Something went wrong");
t.getMessage(); // "Something went wrong"
t.printStackTrace(); // Друкує стек викликів у System.err
t.getCause(); // Повертає причину (якщо є)
t.getStackTrace(); // Масив StackTraceElement[]
Коли використовувати
Безпосередньо Throwable використовується рідко. Зазвичай працюють з його спадкоємцями:
Exceptionі підкласи — для помилок додаткуErrorі підкласи — для фатальних помилок JVM (але їх не ловлять)
Middle Level
Коли НЕ використовувати catch(Throwable)
Ніколи не використовуйте catch (Throwable t) у бізнес-логіці – це перехопить OutOfMemoryError і залишить JVM у нестабільному стані. Виняток: глобальний обробник на межі додатку.
Внутрішній устрій
Throwable містить приховане поле backtrace (тип Object), яке заповнюється нативним методом fillInStackTrace(). Це поле зберігає нативний стек викликів у пам’яті JVM.
При виклику getStackTrace() нативна структура перетворюється на масив StackTraceElement[] — це ледача оптимізація.
Конструктор з контролем стек-трейсу
public Throwable(String message,
Throwable cause,
boolean enableSuppression,
boolean writableStackTrace)
Параметри:
enableSuppression— чи дозволяти suppressed exceptions // Suppressed exceptions – див. файл ‘Що таке suppressed exceptions.md’. // Коротко: якщо в try впав один виняток, а в close() – інший, // другий не втрачається, а додається у suppressed-список першого.writableStackTrace— чи заповнювати стек-трейс
Suppressed Exceptions
Механізм для збереження “втрачених” винятків:
try (FileInputStream fis = new FileInputStream("file.txt")) {
fis.read(); // IOException #1
} // close() кидає IOException #2
// #1 — основний, #2 — suppressed
При логуванні через Logback/Log4j2 suppressed винятки виводяться з префіксом Suppressed:.
Серіалізація
При передачі по мережі (RMI, мікросервіси) нативний backtrace втрачається. JVM конвертує його у Java-об’єкти, що збільшує розмір даних.
Senior Level
Вимкнення стек-трейсу для продуктивності
Для винятків-сигналів (валідація) стек-трейс не потрібен:
public class FastException extends RuntimeException {
public FastException(String message) {
super(message, null, true, false); // writableStackTrace = false
}
}
Прискорює створення у десятки разів — нативний обхід стека не виконується.
Immutable Exceptions
У високонавантажених системах створюють статичні екземпляри:
public static final ValidationException INVALID_EMAIL =
new ValidationException("Invalid email", null, true, false);
Переваги: не створює об’єкти на кожен виклик, немає навантаження на GC. Недоліки: однаковий стек-трейс у всіх випадків.
Розподілені системи
Передача повних стек-трейсів — антипатерн:
// На межі сервісу
try {
service.process();
} catch (Throwable t) {
// Передаємо лише DTO, а не весь стек
return ErrorResponse.of(t.getClass().getSimpleName(), t.getMessage());
}
Економить мегабайти трафіку при масових збоях.
printStackTrace() — ніколи у продакшні
printStackTrace() пише у System.err, який:
- Синхронізований — блокування потоків
- Не потрапляє у лог-файли без редиректу
- У Kubernetes розбивається на окремі рядки
Використовуйте логери: log.error("Msg", throwable).
Діагностика
toString()— лише ім’я класу та повідомленняprintStackTrace()— все дерево (повільно)getStackTrace()— масив елементів (для програмного аналізу)- У розподілених системах використовуйте
Trace ID / Span IDдля зв’язку логів між сервісами
🎯 Шпаргалка для співбесіди
Обов’язково знати:
Throwable— базовий клас для всіх об’єктів, які можнаthrowіcatch- Спадкоємці:
Error(фатальні JVM) таException(помилки додатку) - Зберігає стан: стек-трейс, повідомлення, причину (
cause), suppressed-список - Ключові методи:
getMessage(),getCause(),getStackTrace(),printStackTrace() - Містить приховане поле
backtrace, заповнюване нативнимfillInStackTrace() - Конструктор з
writableStackTrace = falseвимикає обхід стека (прискорює у 10-50 разів) - Suppressed exceptions — зберігають винятки з
close()при try-with-resources printStackTrace()— ніколи у продакшні (пише уSystem.err, синхронізований)
Часті уточнюючі запитання:
- Чому Throwable — клас, а не інтерфейс? — Зберігає стан (стек-трейс, cause, suppressed), інтерфейси не зберігають дані
- Коли НЕ використовувати
catch(Throwable)? — У бізнес-логіці: перехопить OutOfMemoryError; допустимо лише у глобальному обробнику - Що таке suppressed exceptions? — Якщо в try і close() впали два винятки, другий додається у suppressed першого
- Чому printStackTrace() поганий для продакшну? — Синхронізований, не потрапляє у лог-файли, у Kubernetes розбивається на рядки
Червоні прапорці (НЕ говорити):
- “Я використовую Throwable замість Exception для всіх помилок” — це перехопить і Error теж
- “printStackTrace() — нормальний спосіб логування” — використовуйте логери
- “Throwable не серіалізується” — серіалізується, але нативний backtrace втрачається
Пов’язані теми:
- [[Що знаходиться на вершині ієрархії винятків]]
- [[В чому різниця між Error та Exception]]
- [[Що таке suppressed exceptions]]
- [[Як правильно логувати винятки]]
- [[Що таке exception chaining]]