Logger slf4j Vorteile der Formatierung mit {} anstelle der Zeichenfolgenverkettung

100

Gibt es einen Vorteil der Verwendung {}anstelle der Verkettung von Zeichenfolgen?

Ein Beispiel aus slf4j

logger.debug("Temperature set to {}. Old temperature was {}.", t, oldT);

anstatt

logger.debug("Temperature set to"+ t + ". Old temperature was " + oldT);

Ich denke, es geht um Geschwindigkeitsoptimierung, da die Auswertung von Parametern (und die Verkettung von Zeichenfolgen) zur Laufzeit abhängig von einer Konfigurationsdatei vermieden werden könnte. Es sind jedoch nur zwei Parameter möglich. Manchmal gibt es keine andere Wahl als die Verkettung von Zeichenfolgen. Ich brauche Ansichten zu diesem Thema.

Hernán Eche
quelle

Antworten:

74

Es geht um die Verkettungsleistung von Zeichenfolgen. Dies ist möglicherweise von Bedeutung, wenn Sie über umfangreiche Protokollierungsanweisungen verfügen.

(Vor SLF4J 1.7) Es sind jedoch nur zwei Parameter möglich

Da die überwiegende Mehrheit der Protokollierungsanweisungen zwei oder weniger Parameter enthält, deckt die SLF4J-API bis Version 1.6 (nur) die meisten Anwendungsfälle ab. Die API-Designer haben seit API-Version 1.7 überladene Methoden mit varargs-Parametern bereitgestellt.

In den Fällen, in denen Sie mehr als 2 benötigen und mit SLF4J vor 1.7 nicht weiterkommen, verwenden Sie entweder die Zeichenfolgenverkettung oder new Object[] { param1, param2, param3, ... }. Es sollten nur wenige vorhanden sein, damit die Leistung nicht so wichtig ist.

Skaffman
quelle
2
Nicht verwendete Zeichenfolgenverkettung (dh Debugging-Anweisungen) sollte vermieden werden. Verwenden Sie entweder die (übermäßig ausführliche, aber effiziente) Überprüfung auf Protokollebene oder den Objektarray-Parameter (schlanker, aber möglicherweise geringfügiger Overhead). (Ich würde Letzteres bevorzugen, da alle Dinge gleich sind.) Es ist schwer zu sagen, dass die String-Concats nicht wichtig sind / die Leistung nicht beeinträchtigen. Die Objektarray-Erstellung könnte theoretisch weg inline und optimiert werden und "wirklich" keinen Unterschied machen (im Vergleich zu Wunschdenken). (Es ist keine vorzeitige Optimierung, es geht einfach darum, beim ersten Mal etwas richtig / besser zu machen.)
Michael
Warum werden überladene Änderungen nicht vorgenommen, damit System.out.println () ähnlich wie der Logger von slf4j folgt, um die Verkettung von Zeichenfolgen zu vermeiden?
a3.14_Infinity
44

Kurzfassung: Ja, es ist schneller, mit weniger Code!

Die Verkettung von Zeichenfolgen erledigt viel Arbeit, ohne zu wissen, ob sie benötigt wird oder nicht (der herkömmliche Test "ist debugging-fähig", der aus log4j bekannt ist) und sollte nach Möglichkeit vermieden werden, da mit {} der Aufruf von toString () und die Zeichenfolgenkonstruktion verzögert werden können bis nachdem entschieden wurde, ob das Ereignis erfasst werden muss oder nicht. Durch das Logger-Format einer einzelnen Zeichenfolge wird der Code meiner Meinung nach sauberer.

Sie können beliebig viele Argumente angeben. Beachten Sie, dass Sie, wenn Sie eine alte Version von sljf4j verwenden und mehr als zwei Argumente haben {}, new Object[]{a,b,c,d}stattdessen die Syntax verwenden müssen, um ein Array zu übergeben. Siehe z. B. http://slf4j.org/apidocs/org/slf4j/Logger.html#debug(java.lang.String, java.lang.Object []) .

In Bezug auf die Geschwindigkeit: Ceki hat vor einiger Zeit einen Benchmark auf einer der Listen veröffentlicht.

Thorbjørn Ravn Andersen
quelle
6
Hinweis: Das neueste Javadoc zeigt die neuere Var-Arg-Syntax debug(String format, Object... arguments). Siehe slf4j.org/faq.html#logging_performance
michael
Upvoted wegen Erwähnung der .toString () - Evaluierung zusätzlich zur Verkettungsleistung. Dies geschieht im Logger, und der Logger kann entscheiden, ob diese Methode aufgerufen werden muss. Dies ist nicht der Fall, wenn die Protokollierungsstufenleiste nicht erfüllt ist.
Chetan Narsude
6

Da String in Java unveränderlich ist , müssen der linke und der rechte String für jedes Verkettungspaar in den neuen String kopiert werden. Also besser für den Platzhalter gehen.

Rabin Pantha
quelle
2
Dies ist richtig, wenn es ein einzelnes Paar gibt, aber im Allgemeinen falsch, da der Compiler die Verkettung in String-Builder-Aufrufe umwandelt, was zu einem viel schnelleren Code führt, der nicht so viel Zuordnung vornimmt.
Cdeszaq
3

Eine andere Alternative ist String.format(). Wir verwenden es in jcabi-log (statischer Dienstprogramm-Wrapper um slf4j).

Logger.debug(this, "some variable = %s", value);

Es ist viel wartbarer und erweiterbarer. Außerdem ist es einfach zu übersetzen.

yegor256
quelle
3
Ich denke nicht, dass es wartbarer ist. Wenn sich die Art der valueÄnderung ändert, müssen Sie zurückgehen und auch die Protokollierungsanweisung ändern. Etwas, bei dem IDEs Ihnen nicht helfen werden. Logger sollten beim Debuggen helfen und nicht in die Quere kommen. :-)
Chetan Narsude
3
@ChetanNarsude IntelliJ 2016 sagt mir zumindest, wann die Formatzeichenfolge nicht zu den Formatierungsargumenten passt. Beispiel: String.format("%d", "Test")Erzeugt die IntelliJ-Warnung Argument type 'String' does not match the type of the format specifier '%d'.. Ich bin mir jedoch nicht sicher, ob diese intelligente Antwort bei der Arbeit mit der oben genannten Lösung noch möglich ist.
Crush
Wie schnell ist das?
Thorbjørn Ravn Andersen
@ ThorbjørnRavnAndersen es ist innen ziemlich primitiv, aber natürlich ist es langsamer als ein statischer Logger
yegor256
Slf4j einwickeln? Besiegt das nicht den Zweck der Verwendung von slf4j? Außerdem haben viele Leute String.format so missbraucht, dass der String formatiert wird, bevor die Protokollebene ausgewertet wird, z. B.: Logger.info (String.format ("Hallo% s", Benutzername)).
Juan Bustamante
2

Ich denke, aus Sicht des Autors besteht der Hauptgrund darin, den Overhead für die Verkettung von Zeichenfolgen zu reduzieren. Ich habe gerade die Dokumentation des Loggers gelesen, Sie könnten folgende Wörter finden:

/**
* <p>This form avoids superfluous string concatenation when the logger
* is disabled for the DEBUG level. However, this variant incurs the hidden
* (and relatively small) cost of creating an <code>Object[]</code> before 
  invoking the method,
* even if this logger is disabled for DEBUG. The variants taking
* {@link #debug(String, Object) one} and {@link #debug(String, Object, Object) two}
* arguments exist solely in order to avoid this hidden cost.</p>
*/
*
 * @param format    the format string
 * @param arguments a list of 3 or more arguments
 */
public void debug(String format, Object... arguments);
Tianhao Wang
quelle