Warum ist die Verwendung von System.out.println () so schlecht? [geschlossen]
18
Natürlich ist es sehr sinnvoll, ein Protokollierungsframework für die Fehlermeldungen oder Warnungen zu verwenden. Aber manchmal verwende ich System.out.println (), wenn ich in kurzer Zeit etwas Neues ausprobieren möchte.
Ist es wirklich so schlimm, System.out.println () für einen kurzen Test zu verwenden?
Nein, es ist ein schneller Test, wen interessiert das?
Bryan Boettcher
10
Wer sagt, dass es schlecht ist? Was ist die Alternative?
James
1
Die statischen Codeüberprüfungstools von @Kayser eignen sich nicht für schnelle Tests. Sie sind eher für Code gedacht, den Sie mit anderen entwickeln möchten (oder den andere verstehen müssen). Die Lektion, die ich in diesem Jahr zu lernen scheine, ist, dass es sehr unterschiedliche Problembereiche gibt, sogar während des Arbeitstages, die sehr unterschiedliche Toolsets und Praktiken erfordern. Also für Ihren schnellen Test, werfen Sie alles und verwenden Sie Groovy :)
Bill K
1
Versuchen Sie es mit System.err.println()und sehen Sie, was passiert. Ich vermute, dass das Tool denkt, dass Sie es System.outfür den falschen Zweck verwenden.
Izkata
2
Das Hauptproblem liegt in der Skalierbarkeit und Kontrolle. Wenn Sie Millionen solcher Aussagen haben, wie können Sie dann sehen, was Sie sehen müssen? Wenn Sie auf eine dieser Fragen reagieren müssen, wie können Sie dies programmatisch tun? Protokollierungsframeworks sind normalerweise die beiden Gedanken, die auf System.out angewendet werden.
Antworten:
18
Wie aus Kommentaren hervorgeht, lautet die eigentliche Frage: Warum kennzeichnen statische Codeanalyse-Tools die Verwendung von System.out.println?
Der Grund dafür ist, dass das Senden von Nachrichten an stdout in einer Produktionsumgebung normalerweise unangemessen ist. Wenn Sie eine Bibliothek codieren, sollte die Bibliothek Informationen an ihren Aufrufer zurückgeben und nicht an stdout drucken. Wenn Sie eine GUI-App codieren, sollten die Informationen dem Benutzer angezeigt werden und nicht, wohin stdout zeigt (was möglicherweise nirgendwo liegt). Wenn Sie einen Server codieren (oder etwas, das in einem serverseitigen Container ausgeführt wird), sollten Sie die vom Framework bereitgestellte Protokollierungsfunktion verwenden. Und so weiter.
Aber wenn Sie println für das Debuggen oder Entwickeln verwenden oder ein Programm schreiben und stdin lesen und in stdout schreiben, ist println vollkommen in Ordnung. Es ist nichts falsch daran für diese Art von Fällen.
Gute Antwort. Thanks .. +1 for "Wenn Sie eine GUI-App codieren, sollten die Informationen dem Benutzer angezeigt werden und nicht, wohin stdout zeigt (was nirgendwo sein könnte)"
Kayser
10
Alles stdoutist gepuffert, und daher ist es möglich, dass Ihr Programm abstürzt, nachdem Sie es aufgerufen haben println(), aber bevor es den Bildschirm erreicht.
Vor diesem Hintergrund ist dieses Szenario sehr unwahrscheinlich. Mach weiter und benutze es, aber behalte diese kleine Einschränkung im Hinterkopf.
Mindestens zwei große Python-Interpreter sind sehr bemüht, alle geöffneten Dateien vor dem Beenden zu löschen, selbst wenn der Beenden aufgrund einer nicht gehandelten Ausnahme erfolgt. Tun JVMs nicht etwas Ähnliches?
1
@delnan, Möglicherweise kann aber alles passieren. (Der Code, mit dem stdout gelöscht wird, könnte sich an der Stelle befinden, an der das Problem auftritt. Der Thread, in dem Sie ausgeführt werden, könnte zwangsweise geschlossen werden. Der aktuelle Prozess könnte vom Betriebssystem zwangsweise aus dem Speicher abgelegt werden.) Sei dir dessen einfach bewusst.
Riwalk
1
Der Code, der stdout löscht, befindet sich in der VM selbst und ist daher von Fehlern in der von der VM implementierten Sprache nicht betroffen. Guter Punkt zum erzwungenen Prozessende. Beachten Sie jedoch, dass z. B. das SIGTERM-Signal von Unix und die meisten anderen Signale abgefangen werden können, um eine Bereinigung wie folgt durchzuführen - dies funktioniert jedoch nicht mit dem extremeren SIGKILL.
2
Ich glaube nicht, dass ich das jemals gesehen oder gehört habe, obwohl ich andere Probleme gesehen habe. Dieses Problem wird wahrscheinlich auch mit Tools wie Loggern nicht besser, da sie wahrscheinlich System.out als zugrunde liegendes Tool verwenden.
System.outist nur eine verpackte BufferedOutputStream. Dies ähnelt wahrscheinlich jedem Protokollierungsframework, das Sie verwenden. Die Frameworks bieten lediglich mehr Funktionen in Form von Konfiguration und Ziel Ihrer Protokollausgabe
Die meisten IDEs sollten Hotkeys zum automatischen Vervollständigen von System.out.printlns, Kommentieren / Kommentieren einer Zeile und Löschen einer Zeile haben. Sie haben grundsätzlich Recht, eine übermäßige Nutzung zu vermeiden, aber Sie können auf diese Weise zumindest Zeit sparen.
Steven
7
Es gibt ein paar Einschränkungen bei der Verwendung System.out, auch im Wegwerfcode.
Ein Hauptproblem ist, dass es normalerweise langsam ist . Wenn Sie beispielsweise versuchen, eine ungefähre Vorstellung von der Geschwindigkeit eines Codes zu bekommen (beachten Sie, dass Mikrobenchmarks hart sind ), kann das Hinzufügen eines Codes an einer System.out.println()beliebigen Stelle Ihr Timing erheblich verkomplizieren (da er synchronisiert und häufig auf die tatsächliche Ausgabe wartet) für den Benutzer sichtbar sein, bevor er zurückkehrt).
Davon abgesehen würde ich mir im Wegwerfcode nicht allzu viele Sorgen machen. Wenn Sie beabsichtigen, es festzuschreiben (sei es als Produktionscode oder als Testcode), sollten Sie es loswerden und durch einen korrekten Protokollierungsaufruf ersetzen (ja, sogar im Testcode ).
Wie so oft lautet die Antwort „es kommt darauf an“. Wenn in Ihrer Anwendung bereits ein Protokollierungsframework vorhanden ist, können Sie es auch verwenden. Es kann nicht sein weniger leistungsfähig sein als println()und Sie können von anderen Funktionen profitieren, die es bietet - Stapelverfolgung, zusätzlicher Kontext, bessere Formatierung und so weiter. Es besteht auch die eindeutige Möglichkeit, dass Protokollierungsframeworks eine bessere Fehlerbehebung bieten, um sicherzustellen, dass Ihre Protokolle auch bei einem katastrophalen Fehler erfolgreich geschrieben werden.
Die Frage ist also, wann überhaupt ein Protokollierungssystem hinzugefügt werden muss. Dies ist ein Urteilsspruch: Sie möchten es nicht zu früh hinzufügen, nur um herauszufinden, dass Sie es wirklich nicht brauchen. Sie möchten es auch nicht zu spät hinzufügen und übermäßige Konvertierungsarbeiten von Ihrer Ad-hoc-Lösung ausführen.
Wenn Sie feststellen, dass Sie viel mit der Protokollierung zu tun haben println(), versucht Ihre Codebasis, Ihnen mitzuteilen, dass es wachsende Schmerzen gibt. An diesem Punkt lohnt es sich, in eine ordnungsgemäße Protokollierung zu investieren.
Ich habe oft das Problem, dass System.out.print die "system default" -Codepage verwendet, die unter Linux oft UTF-8 ist, unter Windows aber ein paar verdorbene MS-Sachen.
Dies kann dazu führen, dass Unicode-Zeichen auf dem Bildschirm angezeigt werden oder nicht, je nachdem, wo das Programm ausgeführt wird.
Ich bevorzuge daher einen benutzerdefinierten PrintWriter gegenüber System.out
Durch beschissenes MS Zeug. Du meinst CP1352 oder UTF16?
Cole Johnson
@ColeJohnson: Das Windows-Konsolenfenster steckt leider noch in einer Zeit vor UTF16 fest. Die Verwendung einer vernünftigen IDE mit integrierter Konsole kann dieses Problem jedoch verringern.
Joachim Sauer
@Cole Johnson - Ich könnte mit CP 65001 (dh utf8) leben, aber es scheint keine Möglichkeit zu geben, diese Codepage als "Systemstandard" zu erhalten, wenn Sie beispielsweise eine deutsche Tastatur haben, die Sie mit CP 850 oder einer ähnlichen Codepage erhalten.
Ingo
1
Es ist überhaupt nicht schlecht. Der Grund dafür ist möglicherweise, dass es sehr einfach und nicht so ausgefeilt ist wie die Verwendung eines dedizierten Protokollierungsframeworks in Ihrer Anwendung.
Dies bedeutet jedoch nicht, dass es sich um einen ungültigen Ansatz handelt. Ich habe es oft benutzt, um den Anwendungsfluss nach einigen Hijinks mit Black Magic Voodoo- Programmierung zu überprüfen.
Das größte Problem mit dem gelegentlichen System.out.println ist, wie ich es sehe, dass es ein "schlechter Gewohnheitsgeruch (TM)" ist. Wenn Sie dies bemerken, können Sie wahrscheinlich Ihre Effektivität verbessern, indem Sie sich mit Ihrem bevorzugten Debugger wohler fühlen.
Auch mit einem Debugger können Sie sicher sein, dass ein Haltepunkt nicht in Ihren Produktionscode passt, während ein System.out.println dies könnte.
Wenn Sie nur einen kurzen Test durchführen und weiterhin keinen Debugger verwenden, ist System.out.println meiner Meinung nach besser als die Verwendung eines Protokollierungsframeworks, da Sie versehentlich eine log.debug-Anweisung hinterlassen, wenn Sie dies tun fertig, es ist schwerer auszurotten.
Eine komplette Teststrategie zu entwickeln, die den Inhalt des internen Zustands wiedergibt, ist nicht die klügste Methode, aber für schnelle und schmutzige Code-Tests in der Entwicklung schadet es hier und da nicht, wenn Sie daran denken, sie zu entfernen!
Die Gefahr des Vergessens, sie zu entfernen, ist wahrscheinlich der Grund, warum davon abgeraten wird.
Was ist das Problem mit dem Vergessen, sie Ihrer Meinung nach zu entfernen? Sicher gibt es einige Meldungen mehr auf der Konsole. Sehen Sie ein anderes Problem?
System.err.println()
und sehen Sie, was passiert. Ich vermute, dass das Tool denkt, dass Sie esSystem.out
für den falschen Zweck verwenden.Antworten:
Wie aus Kommentaren hervorgeht, lautet die eigentliche Frage: Warum kennzeichnen statische Codeanalyse-Tools die Verwendung von System.out.println?
Der Grund dafür ist, dass das Senden von Nachrichten an stdout in einer Produktionsumgebung normalerweise unangemessen ist. Wenn Sie eine Bibliothek codieren, sollte die Bibliothek Informationen an ihren Aufrufer zurückgeben und nicht an stdout drucken. Wenn Sie eine GUI-App codieren, sollten die Informationen dem Benutzer angezeigt werden und nicht, wohin stdout zeigt (was möglicherweise nirgendwo liegt). Wenn Sie einen Server codieren (oder etwas, das in einem serverseitigen Container ausgeführt wird), sollten Sie die vom Framework bereitgestellte Protokollierungsfunktion verwenden. Und so weiter.
Aber wenn Sie println für das Debuggen oder Entwickeln verwenden oder ein Programm schreiben und stdin lesen und in stdout schreiben, ist println vollkommen in Ordnung. Es ist nichts falsch daran für diese Art von Fällen.
quelle
Alles
stdout
ist gepuffert, und daher ist es möglich, dass Ihr Programm abstürzt, nachdem Sie es aufgerufen habenprintln()
, aber bevor es den Bildschirm erreicht.Vor diesem Hintergrund ist dieses Szenario sehr unwahrscheinlich. Mach weiter und benutze es, aber behalte diese kleine Einschränkung im Hinterkopf.
quelle
System.out
ist nur eine verpackteBufferedOutputStream
. Dies ähnelt wahrscheinlich jedem Protokollierungsframework, das Sie verwenden. Die Frameworks bieten lediglich mehr Funktionen in Form von Konfiguration und Ziel Ihrer Protokollausgabequelle
Es ist schlecht, wenn Sie an einem nicht trivialen Programm arbeiten und Sie
quelle
Es gibt ein paar Einschränkungen bei der Verwendung
System.out
, auch im Wegwerfcode.Ein Hauptproblem ist, dass es normalerweise langsam ist . Wenn Sie beispielsweise versuchen, eine ungefähre Vorstellung von der Geschwindigkeit eines Codes zu bekommen (beachten Sie, dass Mikrobenchmarks hart sind ), kann das Hinzufügen eines Codes an einer
System.out.println()
beliebigen Stelle Ihr Timing erheblich verkomplizieren (da er synchronisiert und häufig auf die tatsächliche Ausgabe wartet) für den Benutzer sichtbar sein, bevor er zurückkehrt).Davon abgesehen würde ich mir im Wegwerfcode nicht allzu viele Sorgen machen. Wenn Sie beabsichtigen, es festzuschreiben (sei es als Produktionscode oder als Testcode), sollten Sie es loswerden und durch einen korrekten Protokollierungsaufruf ersetzen (ja, sogar im Testcode ).
quelle
Wie so oft lautet die Antwort „es kommt darauf an“. Wenn in Ihrer Anwendung bereits ein Protokollierungsframework vorhanden ist, können Sie es auch verwenden. Es kann nicht sein weniger leistungsfähig sein als
println()
und Sie können von anderen Funktionen profitieren, die es bietet - Stapelverfolgung, zusätzlicher Kontext, bessere Formatierung und so weiter. Es besteht auch die eindeutige Möglichkeit, dass Protokollierungsframeworks eine bessere Fehlerbehebung bieten, um sicherzustellen, dass Ihre Protokolle auch bei einem katastrophalen Fehler erfolgreich geschrieben werden.Die Frage ist also, wann überhaupt ein Protokollierungssystem hinzugefügt werden muss. Dies ist ein Urteilsspruch: Sie möchten es nicht zu früh hinzufügen, nur um herauszufinden, dass Sie es wirklich nicht brauchen. Sie möchten es auch nicht zu spät hinzufügen und übermäßige Konvertierungsarbeiten von Ihrer Ad-hoc-Lösung ausführen.
Wenn Sie feststellen, dass Sie viel mit der Protokollierung zu tun haben
println()
, versucht Ihre Codebasis, Ihnen mitzuteilen, dass es wachsende Schmerzen gibt. An diesem Punkt lohnt es sich, in eine ordnungsgemäße Protokollierung zu investieren.quelle
Ich habe oft das Problem, dass System.out.print die "system default" -Codepage verwendet, die unter Linux oft UTF-8 ist, unter Windows aber ein paar verdorbene MS-Sachen.
Dies kann dazu führen, dass Unicode-Zeichen auf dem Bildschirm angezeigt werden oder nicht, je nachdem, wo das Programm ausgeführt wird.
Ich bevorzuge daher einen benutzerdefinierten PrintWriter gegenüber System.out
quelle
Es ist überhaupt nicht schlecht. Der Grund dafür ist möglicherweise, dass es sehr einfach und nicht so ausgefeilt ist wie die Verwendung eines dedizierten Protokollierungsframeworks in Ihrer Anwendung.
Dies bedeutet jedoch nicht, dass es sich um einen ungültigen Ansatz handelt. Ich habe es oft benutzt, um den Anwendungsfluss nach einigen Hijinks mit Black Magic Voodoo- Programmierung zu überprüfen.
quelle
Es ist nichts Falsches daran, es hilft dir herauszufinden, was zum Teufel los ist.
Aber wenn Ihre Kollegen / andere Entwickler / Tools Sie lächerlich machen, können Sie immer Logger verwenden oder Junit- Tests starten !
quelle
Das größte Problem mit dem gelegentlichen System.out.println ist, wie ich es sehe, dass es ein "schlechter Gewohnheitsgeruch (TM)" ist. Wenn Sie dies bemerken, können Sie wahrscheinlich Ihre Effektivität verbessern, indem Sie sich mit Ihrem bevorzugten Debugger wohler fühlen.
Auch mit einem Debugger können Sie sicher sein, dass ein Haltepunkt nicht in Ihren Produktionscode passt, während ein System.out.println dies könnte.
Wenn Sie nur einen kurzen Test durchführen und weiterhin keinen Debugger verwenden, ist System.out.println meiner Meinung nach besser als die Verwendung eines Protokollierungsframeworks, da Sie versehentlich eine log.debug-Anweisung hinterlassen, wenn Sie dies tun fertig, es ist schwerer auszurotten.
quelle
Eine komplette Teststrategie zu entwickeln, die den Inhalt des internen Zustands wiedergibt, ist nicht die klügste Methode, aber für schnelle und schmutzige Code-Tests in der Entwicklung schadet es hier und da nicht, wenn Sie daran denken, sie zu entfernen!
Die Gefahr des Vergessens, sie zu entfernen, ist wahrscheinlich der Grund, warum davon abgeraten wird.
quelle