Существует много из материала отказа там , который наводит на мысль , что печать трассировку стека исключения плохая практика.
Например, из проверки RegexpSingleline в Checkstyle:
Эта проверка может использоваться [...] для поиска распространенных плохих методов, таких как вызов ex.printStacktrace ()
Однако я изо всех сил пытаюсь найти что-либо, что дает вескую причину, поскольку, безусловно, трассировка стека очень полезна для отслеживания того, что вызвало исключение. Вещи, о которых я знаю:
Трассировка стека никогда не должна быть видна конечным пользователям (для удобства пользователей и в целях безопасности)
Создание трассировки стека - относительно дорогостоящий процесс (хотя вряд ли он станет проблемой в большинстве «исключительных» обстоятельств).
Многие фреймворки ведения журналов будут печатать трассировку стека для вас (у нас нет и нет, мы не можем легко это изменить)
Печать трассировки стека не является обработкой ошибок. Его следует сочетать с другой регистрацией информации и обработкой исключений.
Какие еще причины позволяют избежать вывода трассировки стека в код?
источник
.printStackTrace()
в вашем коде :)Ответы:
Throwable.printStackTrace()
записывает трассировку стека вSystem.err
PrintStream.System.err
Поток и основной стандарт «ошибка» выходной поток процесса виртуальной машины Java может быть переадресованSystem.setErr()
который изменяет пункт назначения, на который указываетSystem.err
./dev/null
.Исходя из вышеизложенного, вызов
Throwable.printStackTrace()
составляет допустимое (не хорошее / отличное) поведение обработки исключений, толькоSystem.err
переназначили на протяжении всего срока службы приложения,System.err
(и стандартный поток вывода ошибок JVM).В большинстве случаев вышеуказанные условия не выполняются. Можно не знать о другом коде, выполняющемся в JVM, и нельзя предсказать размер файла журнала или продолжительность выполнения процесса, и хорошо продуманная практика ведения журнала будет вращаться вокруг записи файлов журнала, "анализируемых машиной" ( предпочтительная, но необязательная функция в регистраторе) в известном месте назначения, чтобы помочь в поддержке.
Наконец, следует помнить, что выходные данные
Throwable.printStackTrace()
обязательно будут чередоваться с другим записанным контентомSystem.err
(и, возможно, дажеSystem.out
если оба будут перенаправлены в один и тот же файл / устройство). Это раздражение (для однопоточных приложений), с которым нужно иметь дело, поскольку данные об исключениях нелегко проанализировать в таком случае. Хуже того, весьма вероятно, что многопоточное приложение будет создавать очень запутанные журналы, посколькуThrowable.printStackTrace()
не является потокобезопасным .Не существует механизма синхронизации для синхронизации записи трассировки стека
System.err
при одновременном запуске нескольких потоковThrowable.printStackTrace()
. Для решения этой проблемы на самом деле требуется, чтобы ваш код синхронизировался на связанном с ним монитореSystem.err
(а такжеSystem.out
, если целевой файл / устройство одинаковы), и это довольно высокая цена, которую нужно заплатить за работоспособность файла журнала. Возьмем пример, тоConsoleHandler
иStreamHandler
классы отвечают за добавление записей журнала в консоли, в лесозаготовительной, заложенногоjava.util.logging
; фактическая операция публикации записей журнала синхронизируется - каждый поток, который пытается опубликовать запись журнала, также должен получить блокировку на мониторе, связанном сStreamHandler
пример. Если вы хотите иметь такую же гарантию наличия не чередующихся записей журнала с использованиемSystem.out
/System.err
, вы должны обеспечить то же самое - сообщения публикуются в этих потоках сериализуемым способом.Учитывая все вышеперечисленное и очень ограниченные сценарии, в которых
Throwable.printStackTrace()
это действительно полезно, часто оказывается, что его вызов - плохая практика.Расширяя аргумент в одном из предыдущих абзацев, это также плохой выбор для использования
Throwable.printStackTrace
вместе с регистратором, который записывает в консоль. Частично это связано с тем, что регистратор будет синхронизироваться на другом мониторе, в то время как ваше приложение (возможно, если вы не хотите, чтобы записи журнала чередовались) синхронизировалось на другом мониторе. Этот аргумент также применим, когда вы используете в приложении два разных регистратора, которые записывают в одно и то же место назначения.источник
System.out.println
и,Throwable.printStackTrace
конечно же, требуется мнение разработчика. Я был немного обеспокоен тем, что пропущена часть о безопасности потоков. Если вы посмотрите на большинство реализаций регистраторов, вы заметите, что они синхронизируют часть, в которую записываются записи журнала (даже на консоль), хотя они не получают мониторы наSystem.err
илиSystem.out
.Здесь вы затрагиваете несколько вопросов:
Да, он должен быть доступен для диагностики проблем конечных пользователей, но конечный пользователь не должен их видеть по двум причинам:
Генерация трассировки стека происходит, когда создается / генерируется исключение (поэтому за генерирование исключения приходится платить), печать не так уж и дорога. Фактически, вы можете переопределить
Throwable#fillInStackTrace()
в своем собственном исключении, что фактически сделает выброс исключения почти таким же дешевым, как простой оператор GOTO.Очень хороший момент. Основная проблема здесь: если фреймворк регистрирует исключение для вас, ничего не делайте (но убедитесь, что это так!) Если вы хотите зарегистрировать исключение самостоятельно, используйте фреймворк журналирования, такой как Logback или Log4J , чтобы не помещать их в необработанную консоль потому что это очень трудно контролировать.
С помощью фреймворка ведения журнала вы можете легко перенаправить трассировку стека в файл, консоль или даже отправить их на указанный адрес электронной почты. С жестко заданной программой
printStackTrace()
вам придется жить сsysout
.Еще раз: ведите журнал
SQLException
правильно (с полной трассировкой стека, используя структуру ведения журнала) и показывайте красиво: « Извините, в настоящее время мы не можем обработать ваш запрос ». Вы действительно думаете, что пользователя интересуют причины? Вы видели экран ошибки StackOverflow? Это очень юмористическое, но не раскрывает никаких подробностей. Однако это гарантирует пользователю, что проблема будет исследована.Но он будет звонить вам немедленно , и вы должны быть в состоянии диагностировать проблему. Так что вам нужно и то, и другое: правильная регистрация исключений и удобные сообщения.
В заключение: всегда регистрировать исключения (желательно, используя структуру ведения журнала ), но не раскрывать их конечному пользователю. Тщательно продумайте сообщения об ошибках в вашем графическом интерфейсе, показывайте трассировки стека только в режиме разработки.
источник
Первым делом printStackTrace () не затрат, как вы утверждаете, потому что трассировка стека заполняется при создании самого исключения.
Идея состоит в том, чтобы передавать все, что попадает в журналы, через платформу логгера, чтобы можно было контролировать ведение журнала. Следовательно, вместо использования printStackTrace просто используйте что-то вроде
Logger.log(msg, exception);
источник
Сама по себе печать трассировки стека исключения не является плохой практикой, а только вероятно, проблема здесь заключается печати трассировки стека при возникновении исключения - часто просто печати трассировки стека недостаточно.
Кроме того, существует тенденция подозревать, что правильная обработка исключений не выполняется, если все, что выполняется в
catch
блоке, является файломe.printStackTrace
. Неправильное обращение может означать, что в лучшем случае проблема игнорируется, а в худшем - программа, которая продолжает выполняться в неопределенном или неожиданном состоянии.пример
Рассмотрим следующий пример:
Здесь мы хотим выполнить некоторую обработку инициализации, прежде чем мы продолжим некоторую обработку, которая требует, чтобы инициализация имела место.
В приведенном выше коде исключение должно быть перехвачено и должным образом обработано, чтобы предотвратить переход программы к
continueProcessingAssumingThatTheStateIsCorrect
методу, который, как мы могли предположить, вызовет проблемы.Во многих случаях
e.printStackTrace()
это указание на то, что какое-то исключение проглатывается и обработка разрешена, как если бы не возникало никаких проблем.Почему это стало проблемой?
Вероятно, одна из основных причин того, что плохая обработка исключений стала более распространенной, связана с тем, как IDE, такие как Eclipse, будут автоматически генерировать код, который будет выполнять
e.printStackTrace
для обработки исключений:(Вышеупомянутое является фактическим
try-catch
автоматически сгенерированным Eclipse для обработкиInterruptedException
брошенногоThread.sleep
.)Для большинства приложений простой печати трассировки стека до стандартной ошибки, вероятно, будет недостаточно. Неправильная обработка исключений во многих случаях может привести к тому, что приложение будет работать в неожиданном состоянии и может привести к неожиданному и неопределенному поведению.
источник
Я думаю, что ваш список причин довольно обширен.
Один особенно плохой пример, с которым я сталкивался не раз, звучит так:
Проблема с приведенным выше кодом заключается в том, что обработка полностью состоит из
printStackTrace
вызова: на самом деле исключение не обрабатывается должным образом и ему не разрешено уйти.С другой стороны, как правило, я всегда записываю трассировку стека всякий раз, когда в моем коде возникает непредвиденное исключение. За прошедшие годы эта политика сэкономила мне много времени на отладку.
Наконец, на более легкой ноте : Совершенное исключение Бога .
источник
printStackTrace()
печатает на консоль. В производственных условиях на это никто никогда не смотрит. Сурадж прав, должна передать эту информацию регистратору.источник
В серверных приложениях stacktrace разрушает ваш файл stdout / stderr. Он может становиться все больше и больше и заполняться бесполезными данными, потому что обычно у вас нет контекста, отметки времени и так далее.
например, catalina.out при использовании tomcat в качестве контейнера
источник
Это не плохая практика, потому что с PrintStackTrace () что-то «не так», а потому, что это «запах кода». В большинстве случаев вызов PrintStackTrace () возникает из-за того, что кто-то не смог должным образом обработать исключение. После того, как вы обработаете исключение должным образом, вы, как правило, больше не заботитесь о StackTrace.
Кроме того, отображение трассировки стека на stderr обычно полезно только при отладке, а не в производстве, потому что очень часто stderr никуда не ведет. Логирование имеет больше смысла. Но простая замена PrintStackTrace () на регистрацию исключения по-прежнему оставляет вам приложение, которое не удалось, но продолжает работать, как будто ничего не произошло.
источник
Как некоторые ребята уже упоминал здесь проблема с глотанием исключения в случае , если вы просто звоните
e.printStackTrace()
вcatch
блоке. Это не остановит выполнение потока и продолжится после блока try, как в нормальном состоянии.Вместо этого вам нужно либо попытаться восстановиться после исключения (в случае, если оно может быть восстановлено), либо выбросить
RuntimeException
, либо передать исключение вызывающей стороне, чтобы избежать сбоев без вывода сообщений (например, из-за неправильной конфигурации регистратора).источник
Чтобы избежать запутанной проблемы с выходным потоком, упомянутой @Vineet Reynolds
вы можете распечатать его на стандартный вывод:
e.printStackTrace(System.out);
источник