Почему следует избегать использования System.exit() в Java-приложениях?

«Почему следует избегать использования System.exit() в Java-приложениях?» — вопрос из категории Java Core, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Вызов System.exit(int status) приводит к немедленному завершению работы JVM, что нарушает нормальный жизненный цикл приложения и считается плохой практикой, особенно в серверных и enterprise-приложениях.

Основные проблемы:

  • Некорректное освобождение ресурсов: Потоки (Thread), соединения с БД, сетевые сокеты могут не закрыться корректно, так как хуки завершения (Runtime.addShutdownHook) выполняются, но блоки finally и финализаторы объектов — не гарантированно.
  • Сложность тестирования: Юнит-тест, в котором выполняется код с System.exit(), завершит весь процесс JVM, что сделает автоматическое тестирование невозможным.
  • Нарушение graceful shutdown в контейнерах: В веб-приложениях (Servlet-контейнеры, Spring Boot) это мешает контейнеру корректно завершить работу приложения, остановить пулы потоков и обработать оставшиеся запросы.
  • Скрытие реальной причины ошибки: Вместо явного проброса исключения, которое можно обработать и залогировать, происходит "молчаливое" завершение.

Альтернативы:

// Плохо: Немедленное завершение JVM
if (criticalError) {
    System.exit(1);
}

// Лучше: Использовать исключения для передачи ошибки на верхний уровень
if (criticalError) {
    throw new ApplicationCriticalException("Описание ошибки");
}

// Для Spring Boot приложения:
// 1. Выбросить исключение, которое будет обработано глобальным обработчиком.
// 2. Использовать ApplicationContext.close() для программного завершения.
// 3. Возвращать соответствующий HTTP-статус (например, 500) из контроллера.