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?

Kayser
quelle
3
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.

Stuart Marks
quelle
3
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.

riwalk
quelle
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.
Bill K
@delnan Niemals davon ausgehen, dass Ihr Bereinigungscode garantiert ausgeführt wird ... und niemals kritischen Geschäftstransaktionscode in endgültige Blöcke schreiben.
Steven
8

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

spinning_plate
quelle
4
Dies beantwortet die Frage nicht wirklich. "Ist es schlimm?"
Sergserg
@Berg - Weil dieser Teil der Frage vollständig kontextabhängig ist. (oder einfach, nein, es ist nicht schlecht)
spinning_plate
7

Es ist schlecht, wenn Sie an einem nicht trivialen Programm arbeiten und Sie

  • Verwenden Sie System.out als Krücke anstelle eines automatisierten Komponententests (JUnit)
  • Verbringen Sie viel Zeit damit, System.out-Anweisungen zu erstellen und zu löschen oder zu kommentieren oder zu kommentieren
Aaron Kurtzhals
quelle
1
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 ).

Joachim Sauer
quelle
Leistung ist ein gutes Argument ..
Kayser
4

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.

Jon Purdy
quelle
3

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

Ingo
quelle
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.

sergserg
quelle
0

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 !

lwm
quelle
0

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.

Buhb
quelle
0

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.

GordonM
quelle
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?
Kayser