В чем разница между ошибкой (Error) и исключением (Exception) в Java?

«В чем разница между ошибкой (Error) и исключением (Exception) в Java?» — вопрос из категории Основы тестирования, который задают на 24% собеседований AQA / Automation. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

В Java Error и Exception — это разные подклассы Throwable, и понимание их различий критично для написания надёжных тестов и корректной обработки сбоев.

Исключения (Exception)

  • Представляют проблемы, которые приложение может и должно обработать.
  • Являются частью бизнес-логики.
  • Две категории:
    1. Проверяемые (Checked) исключения: Наследники Exception (но не RuntimeException). Компилятор требует их обработки (блок try-catch) или объявления в сигнатуре метода (throws). Пример: IOException, SQLException. Используются для ожидаемых ошибок внешних систем.
    2. Непроверяемые (Unchecked) исключения: Наследники RuntimeException. Компилятор не требует их явной обработки. Пример: NullPointerException, IllegalArgumentException, ArrayIndexOutOfBoundsException. Часто указывают на ошибки в логике программы.

Ошибки (Error)

  • Представляют серьёзные, критические проблемы, с которыми приложение обычно не должно пытаться справиться.
  • Указывают на сбои в среде выполнения Java (JVM) или системе.
  • Примеры: OutOfMemoryError (закончилась память), StackOverflowError (бесконечная рекурсия), VirtualMachineError.
  • Обычно их не перехватывают (кроме специфических сценариев логирования/завершения работы).

Пример в тестах:

// 1. Проверяемое исключение (Checked Exception) - тестируем корректную обработку
@Test
public void testFileNotFoundHandling() {
    FileReaderService service = new FileReaderService();
    // Ожидаем, что при отсутствии файла сервис выбросит определённое исключение
    assertThrows(FileNotFoundException.class, () -> {
        service.readFile("non_existent.txt");
    });
}

// 2. Непроверяемое исключение (Unchecked Exception) - тестируем валидацию аргументов
@Test
public void testInvalidInputThrowsException() {
    Calculator calc = new Calculator();
    // Ожидаем, что передача null вызовет IllegalArgumentException
    assertThrows(IllegalArgumentException.class, () -> {
        calc.divide(10, null);
    });
}

// 3. Error - обычно НЕ тестируем специально, но должны понимать причину
// Тест, который потребляет всю память, может упасть с OutOfMemoryError,
// но это не failure теста, а проблема конфигурации среды.

Для QA: В автотестах мы чаще всего проверяем, что код бросает ожидаемые Exception (checked или unchecked) при некорректных условиях. Error же сигнализирует о проблемах в тестовом окружении.