Built-in string formatieren vs string-Verkettung als logging-parameter

Ich bin mit SonarLint, der zeigt mir ein Problem in der folgenden Zeile.

LOGGER.debug("Comparing objects: " + object1 + " and " + object2);

Seite-Hinweis: Die Methode, enthält diese Zeile kann aufgerufen werden, ziemlich oft.

Die Beschreibung für dieses Problem ist

"Voraussetzungen" und die Protokollierung Argumente sollte nicht verlangen, evaluation
(squid:S2629)

Passing message Argumente, die erfordern, dass eine weitere Auswertung in eine Guave
com.google.common.base.Voraussetzungen überprüfen kann, im Ergebnis eine Leistung
Strafe. Das ist, weil, ob oder nicht Sie sind notwendig, jedem argument
muss gelöst werden, bevor die Methode tatsächlich aufgerufen wird.

Ähnlich, vorbei verkettet strings in eine logging-Methode kann auch
entstehen unnötige performance-Einbußen, weil die Verkettung wird
durchgeführt, jedes mal, wenn die Methode aufgerufen wird, ob das Protokoll
Niveau ist niedrig genug, um die Meldung angezeigt.

Stattdessen sollten Sie Ihren code strukturieren zu übergeben, statische oder pre-berechnet
Werte in die Voraussetzungen, Bedingungen zu überprüfen und die Protokollierung der Anrufe.

Insbesondere die integrierten string-Formatierung verwendet werden soll, statt
die string-Verkettung, und wenn die Botschaft ist das Ergebnis einer Methode
Anruf, dann die Voraussetzungen übersprungen werden sollen altoghether, und die
relevant sollte die Ausnahme sein, bedingt geworfen statt.

Nicht Kompatiblen Code Beispiel

logger.log(Level.DEBUG, "Something went wrong: " + message);  //Noncompliant; string concatenation performed even when log level too high to show DEBUG messages

LOG.error("Unable to open file " + csvPath, e);  //Noncompliant

Preconditions.checkState(a > 0, "Arg must be positive, but got " + a); //Noncompliant. String concatenation performed even when a > 0

Preconditions.checkState(condition, formatMessage());  //Noncompliant. formatMessage() invoked regardless of condition

Preconditions.checkState(condition, "message: %s", formatMessage()); //Noncompliant

Konforme Lösung

logger.log(Level.SEVERE, "Something went wrong: %s", message);  //String formatting only applied if needed

logger.log(Level.SEVERE, () -> "Something went wrong: " + message); //since Java 8, we can use Supplier , which will be evaluated lazily

LOG.error("Unable to open file {}", csvPath, e);

if (LOG.isDebugEnabled() {   LOG.debug("Unable to open file " + csvPath, e);  //this is compliant, because it will not evaluate if log level is above debug. }

Preconditions.checkState(arg > 0, "Arg must be positive, but got %d", a);  //String formatting only applied if needed

if (!condition) {   throw new IllegalStateException(formatMessage()); //formatMessage() only invoked conditionally }

if (!condition) {   throw new IllegalStateException("message: " + formatMessage()); }

Bin ich mir nicht 100% sicher, ob ich verstehe dieses Recht. Warum also ist dieses wirklich ein Problem. Vor allem der Teil über die Leistungseinbußen bei Verwendung der string-Verkettung. Da ich oft gelesen, dass die string-Verkettung ist schneller als der Formatierung.

EDIT: Vielleicht kann jemand erklären mir den Unterschied zwischen

LOGGER.debug("Comparing objects: " + object1 + " and " + object2);

UND

LOGGEr.debug("Comparing objects: {} and {}",object1, object2);

ist im hintergrund. Weil ich denke der String wird erstellt, bevor es an die Methode übergeben wird. Richtig? Also für mich gibt es keinen Unterschied. Aber offensichtlich Irre ich mich da SonarLint beschwert sich über es

InformationsquelleAutor Naxos84 | 2017-02-22
Schreibe einen Kommentar