Питання 7 · Розділ 7

В чому різниця між Error та Exception?

Обидва класи успадковуються від Throwable, але означають принципово різні проблеми:

Мовні версії: English Russian Ukrainian

Junior Level

Основна відмінність

Обидва класи успадковуються від Throwable, але означають принципово різні проблеми:

Error – проблеми JVM (не додатку), які зазвичай неможливо виправити.

Виняток: AssertionError технічно Error, але виникає через логіку додатку. Використовується для перевірки інваріантів, а не зовнішніх збоїв.

  • Не під контролем розробника
  • У звичайному коді не ловіть
  • Приклади: OutOfMemoryError, StackOverflowError

Exception — помилки додатку:

  • Очікувані збої, які можна обробити
  • Потрібно обробляти
  • Приклади: IOException, SQLException

У звичайному коді не ловіть Error. Винятки: глобальний обробник потоків (setDefaultUncaughtExceptionHandler), graceful shutdown, health-check механізми.

Візуально

Throwable
  ├── Error        ← JVM зламалася
  └── Exception    ← Додаток зіткнувся з проблемою

Приклади

// Error — додаток безсилий
// java.lang.OutOfMemoryError: Java heap space
List<byte[]> memoryHog = new ArrayList<>();
while (true) memoryHog.add(new byte[1024 * 1024]);

// Exception — можна обробити
try {
    Files.readAllLines(Paths.get("missing.txt"));
} catch (IOException e) {
    System.out.println("File not found, using default");
}

Просте правило

  • Error — “померла JVM” → нехай впаде
  • Exception — “щось пішло не так” → обробити або логувати

Middle Level

OutOfMemoryError — підтипи

OutOfMemoryError буває різних видів:

  • Java heap space — закінчилася купа
  • Metaspace — закінчилася пам’ять під метадані (часто при генерації класів через CGLIB)
  • Unable to create new native thread — ОС заборонила створювати нові потоки

Навіть якщо спіймати OOM, JVM може бути у нестабільному стані.

NoClassDefFoundError vs ClassNotFoundException

Це класичне запитання на співбесіді:

ClassNotFoundException (Exception):

  • Ви явно просите завантажити клас: Class.forName("com.mysql.Driver")
  • Класу немає в classpath
  • Можна обробити

NoClassDefFoundError (Error):

  • Клас був при компіляції, але зник у рантаймі
  • Або його завантаження впало через помилку у статичному блоці
  • Критичний збій середовища

// Якщо у статичному блоці класу: // static { int x = 1/0; } // При першому завантаженні: ExceptionInInitializerError // При наступних спробах: NoClassDefFoundError (клас не був ініціалізований)

AssertionError

Успадковується від Error. Викидається оператором assert (при прапорці -ea):

assert x > 0 : "x must be positive"; // AssertionError якщо x <= 0

Використовуйте assert для перевірки інваріантів алгоритму, не для валідації вхідних даних API — для цього є IllegalArgumentException.

StackOverflowError vs OutOfMemoryError

StackOverflowError vs OutOfMemoryError:

  • StackOverflowError – вичерпано стек (глибока рекурсія). Лікування: збільшити -Xss або виправити рекурсію
  • OutOfMemoryError – вичерпано купу (багато об’єктів). Лікування: збільшити -Xmx або виправити витік

Senior Level

Обробка Error — чому погана практика

Навіть якщо спіймали Error, JVM може перебувати у нестабільному стані. Наступна операція (навіть логування) може викликати новий Error.

Fail Fast & Die патерн

У Highload-системах при Error додаток повинен швидко завершитися:

public static void main(String[] args) {
    Thread.setDefaultUncaughtExceptionHandler((thread, e) -> {
        if (e instanceof Error) {
            log.error("Fatal error in thread {}", thread.getName(), e);
            System.exit(1); // Вмираємо, щоб оркестратор перезапустив
        }
    });
}

Kubernetes або інший оркестратор перезапустить свіжий екземпляр.

JVM прапорець для OOM

-XX:OnOutOfMemoryError="kill -9 %p"

Гарантує смерть процесу при OutOfMemoryError.

StackOverflowError

Частий Error при нескінченній рекурсії. Розмір стеку обмежений -Xss. У глибоких ієрархіях або при циклах в сутностях Hibernate може знадобитися збільшення.

// Нескінченна рекурсія
public int factorial(int n) {
    return n * factorial(n); // StackOverflowError
}

Logging Errors

Якщо ловите Throwable на верхньому рівні (main або UncaughtExceptionHandler), робіть System.exit(1) після логування, щоб не залишити систему у “зомбі-стані”.

Діагностика

  • javap -v — подивіться атрибути методів для розуміння обробки винятків
  • Thread Dumpsjstack <pid> покаже стан усіх потоків при зависанні
  • Heap Dumpsjmap допоможе аналізувати OutOfMemoryError
  • -XX:+HeapDumpOnOutOfMemoryError — автоматичний дамп купи при OOM

🎯 Шпаргалка для співбесіди

Обов’язково знати:

  • Error — проблеми JVM (неможливо виправити), Exception — помилки додатку (можна обробити)
  • Error: OutOfMemoryError, StackOverflowError, NoClassDefFoundError — не ловити
  • Exception поділяється на checked та unchecked (RuntimeException)
  • NoClassDefFoundErrorClassNotFoundException: перший — Error (був при компіляції, немає у рантаймі), другий — Exception (явно вантажили, немає в classpath)
  • AssertionError — технічно Error, але через логіку додатку (перевірка інваріантів)
  • Fail Fast & Die: при Error — System.exit(1), нехай оркестратор перезапустить
  • JVM прапорець -XX:OnOutOfMemoryError="kill -9 %p" гарантує смерть при OOM
  • Thread.setDefaultUncaughtExceptionHandler — перехоплює Error на верхньому рівні

Часті уточнюючі запитання:

  • Чи можна спіймати OutOfMemoryError? — Технічно так, але JVM у нестабільному стані — наступна операція впаде
  • У чому різниця між StackOverflowError та OutOfMemoryError? — StackOverflowError — вичерпано стек (рекурсія), OOM — вичерпано купу (багато об’єктів)
  • Коли AssertionError — це Error, а не Exception? — Тому що assert перевіряє інваріанти алгоритму, а не зовнішні збої
  • Що робити при Error у продакшні? — Логувати і System.exit(1), Kubernetes перезапустить под

Червоні прапорці (НЕ говорити):

  • “Я ловлю Error і продовжую роботу” — JVM нестабільна, це безглуздо
  • “NoClassDefFoundError і ClassNotFoundException — одне й те саме” — ні, перший Error, другий Exception
  • “AssertionError використовується для валідації вхідних даних” — для цього є IllegalArgumentException

Пов’язані теми:

  • [[Що знаходиться на вершині ієрархії винятків]]
  • [[Що таке Throwable]]
  • [[Що таке unchecked виняток (Runtime Exception)]]
  • [[Чи завжди виконується блок finally]]
  • [[Що таке stack trace]]