Вопрос 17 · Раздел 7

Что делает метод printStackTrace()?

printStackTrace() — метод Throwable, который выводит полную информацию об исключении (тип, сообщение, стек вызовов) в System.err.

Версии по языкам: English Russian Ukrainian

Junior Level

Определение

printStackTrace() — метод Throwable, который выводит полную информацию об исключении (тип, сообщение, стек вызовов) в System.err.

Пример

try {
    int x = 10 / 0;
} catch (ArithmeticException e) {
    e.printStackTrace();
    // Вывод: java.lang.ArithmeticException: / by zero
    //         at com.example.Main.main(Main.java:10)
}

Что он показывает

  1. Тип исключения: java.lang.ArithmeticException
  2. Сообщение: / by zero
  3. Стек вызовов: в каком файле, методе и строке произошла ошибка

Когда использовать

  • Только при отладке и прототипировании, когда вам нужно быстро увидеть стек в консоли без настройки логгера
  • Не использовать в продакшен-коде

ПОЧЕМУ printStackTrace() плох для production

printStackTrace() — это «сырой» вывод, который:

  1. Пишет в System.err, а не в ваш лог-файл. В production логи собираются централизованно (ELK, Splunk), а System.err может быть перенаправлен в /dev/null или потерян при перезапуске контейнера
  2. Не добавляет контекст: нет timestamp, trace ID, имени класса — только голый стек. Попробуйте найти нужную ошибку среди тысяч таких же
  3. Разбивает стек на отдельные строки. В Kubernetes каждая строка printStackTrace() становится отдельной JSON-записью в ElasticSearch — вместо одного читаемого лога вы получаете 50 разрозненных
  4. Блокирует потокSystem.err синхронизирован. При высокой нагрузке 100 потоков будут вставать в очередь на запись

Когда НЕ использовать printStackTrace()

  1. Продакшен-код — заменяйте на логгер (log.error("msg", e))
  2. Многопоточные приложенияSystem.err синхронизирован, создаёт contention
  3. Веб-приложения — стек в HTTP-ответе раскрывает внутреннюю структуру (Security)
  4. ELK/Splunk инфраструктурыprintStackTrace() разбивает один стек на 50+ отдельных JSON-записей
  5. Highload-системы — блокировка на System.err при заполненном диске/pipe

Middle Level

Почему это работает медленно

1. Синхронизация: System.err — объект PrintStream. Все его методы используют синхронизацию. В многопоточном приложении 100 потоков будут ждать блокировки.

2. Преобразование нативного стека: Throwable лениво преобразует нативный backtrace в массив StackTraceElement[] именно в момент обращения к стеку.

Вывод в строку

StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String stackTrace = sw.toString();

Сравнение с логгерами

// ПЛОХО — синхронизация, нет контекста, разбивает логи
e.printStackTrace();

// ХОРОШО — асинхронно, с контекстом, JSON-friendly
log.error("Failed to process order id={}", id, e);

Логгеры умеют:

  • Форматировать стек в одну строку или JSON
  • Обрезать слишком длинные стеки
  • Добавлять информацию о JAR-файле и версии
  • Писать в файл, а не в консоль

Куда он пишет на самом деле

В Kubernetes/Docker System.err перехватывается и пишется в JSON-логи. Но printStackTrace() выводит каждую строку как отдельную запись.

Результат: вместо одного лога ошибки — 50 разрозненных строк в ElasticSearch.


Senior Level

Standard I/O blocking

Если диск переполнен или pipe консоли забит, printStackTrace() заблокирует поток выполнения на неопределённое время.

Senior Rule: в продакшн-коде printStackTrace() должен быть запрещён правилами статического анализа (Checkstyle/Sonar).

Circular Causes

При циклической зависимости в cause (хотя initCause это проверяет), printStackTrace имеет защиту и печатает [CIRCULAR REFERENCE], не уходя в бесконечную рекурсию.

Security

Стек-трейс в консоли раскрывает версии библиотек и структуру путей. В веб-приложениях никогда не отдавайте printStackTrace() в HTTP-ответе — используйте @ControllerAdvice.

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

// Программно получить стек как строку
String stackTrace = ExceptionUtils.getStackTrace(e); // Apache Commons

// Логгер
log.error("Context message", e); // Logback/Log4j2

// Thread Dumps — если приложение зависло
// jstack <pid> или jcmd <pid> Thread.print

Диагностика

  • jstack <pid> — состояние всех мониторов и потоков
  • jcmd <pid> Thread.print — альтернатива jstack
  • Статический анализ — Sonar блокирует printStackTrace() в продакшн-коде
  • JSON Layout — логи должны быть в формате JSON для ELK/Splunk

🎯 Шпаргалка для интервью

Обязательно знать:

  • printStackTrace() выводит тип, сообщение и стек вызовов исключения в System.err
  • НЕ использовать в production: пишет в System.err, а не в лог-файл; нет timestamp/trace ID; блокирует поток (синхронизация)
  • В Kubernetes/Docker каждая строка printStackTrace() становится отдельной JSON-записью в ELK — один стек разбивается на 50+ записей
  • System.errPrintStream с синхронизацией; при высокой нагрузке потоки встают в очередь
  • В продакшене заменяйте на log.error("context", e) — асинхронно, с контекстом, JSON-friendly
  • printStackTrace() защищает от циклических причин — печатает [CIRCULAR REFERENCE]

Частые уточняющие вопросы:

  • Почему printStackTrace() плох для production? — 4 причины: пишет в System.err (не в лог), нет контекста, разбивает стек на строки, блокирует поток
  • Как получить стек как строку программно?StringWriter + PrintWriter или ExceptionUtils.getStackTrace(e) из Apache Commons
  • Что происходит при переполнении диска?printStackTrace() заблокирует поток на неопределённое время, т.к. System.err синхронизирован
  • Как в Spring избежать утечки стека в HTTP-ответ? — Использовать @ControllerAdvice, никогда не отдавать printStackTrace() клиенту

Красные флаги (НЕ говорить):

  • “Использую printStackTrace() в production — работает” — Теряете логи, блокируете потоки, раскрываете структуру кода
  • “Разницы между printStackTrace() и логгером нет” — Логгер добавляет контекст, форматирует, пишет в нужное место
  • “Стек в HTTP-ответе — нормальная практика” — Раскрывает версии библиотек и структуру путей (security vulnerability)

Связанные темы:

  • [[15. Что такое stack trace]]
  • [[17. Как правильно логировать исключения]]
  • [[19. Почему не стоит глотать исключения (catch empty)]]
  • [[1. В чём разница между checked и unchecked exceptions]]
  • [[20. Что делает ключевое слово throws]]