Es gibt eine Menge von Material heraus dort , die , dass die Stack - Trace einer Ausnahme Druck legt nahe , ist eine schlechte Praxis.
ZB vom RegexpSingleline-Check in Checkstyle:
Diese Prüfung kann [...] verwendet werden, um gängige schlechte Praktiken wie das Aufrufen von ex.printStacktrace () zu finden.
Ich habe jedoch Schwierigkeiten, irgendwo zu finden, was einen triftigen Grund dafür gibt, da die Stapelverfolgung sicherlich sehr nützlich ist, um herauszufinden, was die Ausnahme verursacht hat. Dinge, die mir bewusst sind:
Ein Stack-Trace sollte für Endbenutzer niemals sichtbar sein (aus Gründen der Benutzererfahrung und Sicherheit).
Das Generieren einer Stapelverfolgung ist ein relativ teurer Prozess (obwohl es unter den meisten "außergewöhnlichen" Umständen unwahrscheinlich ist, dass dies ein Problem darstellt).
Viele Protokollierungsframeworks drucken den Stack-Trace für Sie (bei uns nicht und nein, wir können ihn nicht einfach ändern).
Das Drucken der Stapelverfolgung stellt keine Fehlerbehandlung dar. Es sollte mit anderen Informationsprotokollierungen und Ausnahmebehandlungen kombiniert werden.
Welche anderen Gründe gibt es, um das Drucken eines Stack-Trace in Ihrem Code zu vermeiden?
quelle
.printStackTrace()
jetzt vor der Verwendung in Ihrem Code :)Antworten:
Throwable.printStackTrace()
schreibt den Stack-Trace inSystem.err
PrintStream. DerSystem.err
Stream und der zugrunde liegende Standardausgabestream "Fehler" des JVM-Prozesses können von umgeleitet werdenSystem.setErr()
wodurch das Ziel geändert wird, auf das verwiesen wirdSystem.err
./dev/null
.Daraus folgt, dass das Aufrufen nur
Throwable.printStackTrace()
ein gültiges (nicht gutes / gutes) Verhalten bei der Ausnahmebehandlung darstelltSystem.err
während der gesamten Lebensdauer der Anwendung nicht neu zugewiesen wurden,System.err
(und den Standardfehlerausgabestream der JVM) zu schreiben .In den meisten Fällen sind die oben genannten Bedingungen nicht erfüllt. Man kennt möglicherweise keinen anderen Code, der in der JVM ausgeführt wird, und man kann die Größe der Protokolldatei oder die Laufzeit des Prozesses nicht vorhersagen, und eine gut konzipierte Protokollierungspraxis würde sich darauf konzentrieren, "maschinenparsierbare" Protokolldateien zu schreiben (a bevorzugte, aber optionale Funktion in einem Logger) an einem bekannten Ziel, um die Unterstützung zu unterstützen.
Schließlich sollte man bedenken, dass die Ausgabe von
Throwable.printStackTrace()
definitiv mit anderen Inhalten verschachtelt wird, auf die geschrieben wurdeSystem.err
(und möglicherweise sogar,System.out
wenn beide auf dieselbe Datei / dasselbe Gerät umgeleitet werden). Dies ist ein Ärger (für Single-Threaded-Apps), mit dem man sich befassen muss, da die Daten um Ausnahmen in einem solchen Fall nicht leicht zu analysieren sind. Schlimmer noch, es ist sehr wahrscheinlich, dass eine Multithread-Anwendung sehr verwirrende Protokolle erstellt, da sieThrowable.printStackTrace()
nicht threadsicher ist .Es gibt keinen Synchronisationsmechanismus, mit dem das Schreiben des Stack-Trace synchronisiert werden kann,
System.err
wenn mehrere Threads gleichzeitig aufgerufenThrowable.printStackTrace()
werden. Um dies zu beheben, muss Ihr Code auf dem zugehörigen Monitor synchronisiert werdenSystem.err
(und auchSystem.out
, wenn die Zieldatei / das Gerät identisch ist), und das ist ein ziemlich hoher Preis für die Vernunft von Protokolldateien. Um ein Beispiel zu nehmen, dieConsoleHandler
undStreamHandler
sind Klassen , die für das Anhängen Protokollaufzeichnungen in Konsole, in der Logging - Einrichtung zur Verfügung gestellt vonjava.util.logging
; Der eigentliche Vorgang zum Veröffentlichen von Protokolldatensätzen wird synchronisiert. Jeder Thread, der versucht, einen Protokolldatensatz zu veröffentlichen, muss auch die Sperre für den mit dem verknüpften Monitor erhaltenStreamHandler
Beispiel. Wenn Sie die gleiche Garantie für nicht verschachtelte Protokolldatensätze mitSystem.out
/ haben möchten, müssenSystem.err
Sie dies auch sicherstellen - die Nachrichten werden auf serialisierbare Weise in diesen Streams veröffentlicht.In Anbetracht all dieser Punkte und der sehr eingeschränkten Szenarien, in denen dies
Throwable.printStackTrace()
tatsächlich nützlich ist, stellt sich häufig heraus, dass das Aufrufen eine schlechte Praxis ist.Wenn Sie das Argument in einem der vorherigen Absätze erweitern, ist es auch eine schlechte Wahl, es
Throwable.printStackTrace
in Verbindung mit einem Logger zu verwenden, der auf die Konsole schreibt. Dies liegt zum Teil daran, dass der Logger auf einem anderen Monitor synchronisiert wird, während Ihre Anwendung (möglicherweise, wenn Sie keine verschachtelten Protokolldatensätze wünschen) auf einem anderen Monitor synchronisiert wird. Das Argument gilt auch, wenn Sie in Ihrer Anwendung zwei verschiedene Logger verwenden, die auf dasselbe Ziel schreiben.quelle
System.out.println
undThrowable.printStackTrace
und natürlich Entwickler Abwägen erfordern. Ich war etwas besorgt, dass der Teil über die Thread-Sicherheit übersehen wurde. Wenn Sie sich die meisten Logger-Implementierungen ansehen, werden Sie feststellen, dass sie den Teil synchronisieren, in den Protokolldatensätze geschrieben werden (sogar in die Konsole), obwohl sie keine Monitore aufSystem.err
oder erfassenSystem.out
.Sie berühren hier mehrere Themen:
Ja, es sollte zugänglich sein, um Probleme von Endbenutzern zu diagnostizieren, aber Endbenutzer sollten sie aus zwei Gründen nicht sehen:
Das Generieren einer Stapelverfolgung erfolgt, wenn die Ausnahme erstellt / ausgelöst wird (daher ist das Auslösen einer Ausnahme mit einem Preis verbunden). Das Drucken ist nicht so teuer. Tatsächlich können Sie
Throwable#fillInStackTrace()
Ihre benutzerdefinierte Ausnahme effektiv überschreiben, sodass das Auslösen einer Ausnahme fast so billig ist wie eine einfache GOTO-Anweisung.Sehr guter Punkt. Das Hauptproblem hierbei ist: Wenn das Framework die Ausnahme für Sie protokolliert, tun Sie nichts (aber stellen Sie sicher, dass dies der Fall ist!). Wenn Sie die Ausnahme selbst protokollieren möchten, verwenden Sie das Protokollierungsframework wie Logback oder Log4J , um sie nicht auf der Raw-Konsole abzulegen weil es sehr schwer ist, es zu kontrollieren.
Mit dem Protokollierungsframework können Sie Stack-Traces einfach in Dateien umleiten, konsolidieren oder sogar an eine bestimmte E-Mail-Adresse senden. Mit hardcoded muss
printStackTrace()
man mit dem lebensysout
.Nochmals: Melden Sie sich
SQLException
korrekt an (mit dem vollständigen Stack-Trace unter Verwendung des Protokollierungsframeworks) und zeigen Sie Folgendes an: " Entschuldigung, wir können Ihre Anfrage derzeit nicht verarbeiten ". Denken Sie wirklich, dass der Benutzer an den Gründen interessiert ist? Haben Sie den StackOverflow-Fehlerbildschirm gesehen? Es ist sehr humorvoll, enthüllt aber keine Details. Es stellt jedoch sicher, dass der Benutzer das Problem untersucht.Aber er wird Sie sofort anrufen und Sie müssen in der Lage sein, das Problem zu diagnostizieren. Sie benötigen also beides: eine ordnungsgemäße Ausnahmeprotokollierung und benutzerfreundliche Nachrichten.
Zum Abschluss: Protokollieren Sie Ausnahmen immer (vorzugsweise mithilfe des Protokollierungsframeworks ), setzen Sie sie jedoch nicht dem Endbenutzer zur Verfügung. Denken Sie sorgfältig über Fehlermeldungen in Ihrer GUI nach und zeigen Sie Stack-Traces nur im Entwicklungsmodus an.
quelle
Als erstes ist printStackTrace () nicht teuer, wie Sie angeben , da der Stack-Trace gefüllt wird, wenn die Ausnahme selbst erstellt wird.
Die Idee ist, alles, was zu Protokollen geht, über ein Logger-Framework zu übergeben, damit die Protokollierung gesteuert werden kann. Verwenden Sie daher anstelle von printStackTrace einfach so etwas wie
Logger.log(msg, exception);
quelle
Das Drucken des Stack-Trace der Ausnahme an sich ist keine schlechte Praxis, sondern nur Drucken des Stace-Trace Auftreten einer Ausnahme ist hier wahrscheinlich das Problem. Oft reicht es nicht aus, nur einen Stack-Trace zu drucken.
Es besteht auch die Tendenz zu vermuten, dass keine ordnungsgemäße Ausnahmebehandlung durchgeführt wird, wenn in einem
catch
Block nur a ausgeführt wirde.printStackTrace
. Eine unsachgemäße Behandlung kann bedeuten, dass im besten Fall ein Problem ignoriert wird und im schlimmsten Fall ein Programm, das weiterhin in einem undefinierten oder unerwarteten Zustand ausgeführt wird.Beispiel
Betrachten wir das folgende Beispiel:
Hier möchten wir eine Initialisierungsverarbeitung durchführen, bevor wir mit einer Verarbeitung fortfahren, die erfordert, dass die Initialisierung stattgefunden hat.
Im obigen Code sollte die Ausnahme abgefangen und ordnungsgemäß behandelt worden sein, um zu verhindern, dass das Programm zum
continueProcessingAssumingThatTheStateIsCorrect
Methode wir annehmen könnten, dass sie Probleme verursachen würde.In vielen Fällen
e.printStackTrace()
ist dies ein Hinweis darauf, dass eine Ausnahme verschluckt wird und die Verarbeitung so fortgesetzt werden kann, als ob kein Problem aufgetreten wäre.Warum ist das ein Problem geworden?
Wahrscheinlich ist einer der Hauptgründe dafür, dass eine schlechte Ausnahmebehandlung immer häufiger auftritt, die Tatsache, dass IDEs wie Eclipse automatisch Code generieren, der eine
e.printStackTrace
Ausnahmebehandlung ausführt :(Das Obige ist eine
try-catch
von Eclipse automatisch generierte Version, die von einemInterruptedException
geworfen wirdThread.sleep
.)Für die meisten Anwendungen reicht es wahrscheinlich nicht aus, nur den Stack-Trace auf Standardfehler zu drucken. Eine unsachgemäße Ausnahmebehandlung kann in vielen Fällen dazu führen, dass eine Anwendung in einem unerwarteten Zustand ausgeführt wird und zu unerwartetem und undefiniertem Verhalten führt.
quelle
Ich denke, Ihre Liste der Gründe ist ziemlich umfassend.
Ein besonders schlechtes Beispiel, dem ich mehr als einmal begegnet bin, lautet wie folgt:
Das Problem mit dem obigen Code ist, dass die Behandlung vollständig aus dem
printStackTrace
Aufruf besteht: Die Ausnahme wird nicht richtig behandelt und darf nicht entkommen.Andererseits protokolliere ich in der Regel immer den Stack-Trace, wenn mein Code eine unerwartete Ausnahme enthält. Im Laufe der Jahre hat mir diese Richtlinie viel Zeit beim Debuggen gespart.
Zum Schluss noch Gottes leichtere Ausnahme .
quelle
printStackTrace()
druckt auf eine Konsole. In Produktionsumgebungen sieht das noch niemand. Suraj ist korrekt, sollte diese Informationen an einen Logger weitergeben.quelle
In Serveranwendungen sprengt der Stacktrace Ihre stdout / stderr-Datei. Es kann immer größer werden und ist mit nutzlosen Daten gefüllt, da Sie normalerweise keinen Kontext und keinen Zeitstempel haben und so weiter.
zB Catalina.out bei Verwendung von Tomcat als Container
quelle
Es ist keine schlechte Praxis, weil PrintStackTrace () nicht stimmt, sondern weil es nach Code riecht. Meistens ist der PrintStackTrace () -Aufruf vorhanden, weil jemand die Ausnahme nicht ordnungsgemäß behandelt hat. Sobald Sie die Ausnahme richtig behandelt haben, interessiert Sie die StackTrace im Allgemeinen nicht mehr.
Darüber hinaus ist das Anzeigen des Stacktraces auf stderr im Allgemeinen nur beim Debuggen nützlich, nicht in der Produktion, da stderr sehr oft nirgendwo hinführt. Protokollierung macht mehr Sinn. Wenn Sie jedoch nur PrintStackTrace () durch die Protokollierung der Ausnahme ersetzen, bleibt eine Anwendung erhalten, die fehlgeschlagen ist, aber weiterhin ausgeführt wird, als wäre nichts passiert.
quelle
Wie einige Leute hier bereits erwähnt haben, liegt das Problem mit der Ausnahme des Schluckens, falls Sie nur
e.printStackTrace()
dencatch
Block anrufen . Die Thread-Ausführung wird nicht gestoppt und nach dem try-Block wie im normalen Zustand fortgesetzt.Stattdessen müssen Sie entweder versuchen, die Ausnahme zu beheben (falls sie wiederhergestellt werden kann) oder
RuntimeException
die Ausnahme an den Anrufer zu senden oder zu sprudeln, um stille Abstürze zu vermeiden (z. B. aufgrund einer falschen Logger-Konfiguration).quelle
Um das von @Vineet Reynolds erwähnte Problem des verwickelten Ausgabestreams zu vermeiden
Sie können es auf dem Standard drucken:
e.printStackTrace(System.out);
quelle