Logger slf4j avantages du formatage avec {} au lieu de la concaténation de chaînes


100

Y a-t-il un avantage à utiliser {}au lieu de la concaténation de chaînes?

Un exemple de slf4j

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

au lieu de

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

Je pense que c'est une question d'optimisation de la vitesse, car l'évaluation des paramètres (et la concaténation de chaînes) pourraient être évitées au moment de l'exécution en fonction d'un fichier de configuration. Mais seuls deux paramètres sont possibles, alors parfois il n'y a pas d'autre choix que la concaténation de chaînes. Besoin de points de vue sur cette question.

Réponses:


74

Il s'agit de performances de concaténation de chaînes. C'est potentiellement important si vous avez des instructions de journalisation denses.

(Avant SLF4J 1.7) Mais seuls deux paramètres sont possibles

Comme la grande majorité des instructions de journalisation ont 2 paramètres ou moins, l'API SLF4J jusqu'à la version 1.6 couvre (uniquement) la majorité des cas d'utilisation. Les concepteurs d'API ont fourni des méthodes surchargées avec des paramètres varargs depuis la version 1.7 de l'API.

Pour les cas où vous avez besoin de plus de 2 et que vous êtes bloqué avec SLF4J pré-1.7, utilisez simplement la concaténation de chaînes ou new Object[] { param1, param2, param3, ... }. Il devrait y en avoir suffisamment peu pour que la performance ne soit pas aussi importante.


2
La concaténation de chaînes non utilisée (c'est-à-dire les instructions de débogage) doit être évitée. Utilisez soit la vérification du niveau de journalisation (trop verbeuse mais efficace) ou le paramètre de tableau d'objets (plus mince, mais peut-être une surcharge mineure). (Je préfère ce dernier, toutes choses étant égales par ailleurs.) Il est difficile de dire que le concat de la chaîne ne sera pas important / n'aura pas d'impact sur les performances. La création de tableaux d'objets pourrait en théorie être intégrée et optimisée et ne "vraiment" pas faire de différence (par rapport aux vœux pieux). (Ce n'est pas une optimisation prématurée, il s'agit simplement de faire quelque chose de bien / mieux la première fois.)
michael

pourquoi des modifications surchargées ne sont pas effectuées pour que System.out.println () suive de la même manière que le logger de slf4j, afin d'éviter la concaténation de chaînes?
a3.14_Infinity

44

Version courte: Oui, c'est plus rapide, avec moins de code!

La concaténation de chaînes fait beaucoup de travail sans savoir si elle est nécessaire ou non (le test traditionnel "est le débogage activé" connu de log4j), et doit être évitée si possible, car le {} permet de retarder l'appel toString () et la construction de la chaîne après qu'il a été décidé si l'événement doit être capturé ou non. En ayant le format de l'enregistreur une seule chaîne, le code devient plus propre à mon avis.

Vous pouvez fournir n'importe quel nombre d'arguments. Notez que si vous utilisez une ancienne version de sljf4j et que vous avez plus de deux arguments à {}, vous devez utiliser la new Object[]{a,b,c,d}syntaxe pour passer un tableau à la place. Voir par exemple http://slf4j.org/apidocs/org/slf4j/Logger.html#debug(java.lang.String, java.lang.Object []) .

Concernant la vitesse: Ceki a posté un repère il y a quelque temps sur l'une des listes.


6
Note: les dernières émissions javadoc la nouvelle syntaxe var-arg, debug(String format, Object... arguments). Voir slf4j.org/faq.html#logging_performance
michael

Vote positif en raison de la mention de l'évaluation de .toString () en plus des performances de concaténation. C'est quelque chose qui se produit à l'intérieur de l'enregistreur et l'enregistreur peut décider s'il est nécessaire d'appeler cette méthode. Ce n'est pas le cas si la barre de niveau de journalisation n'est pas respectée.
Chetan Narsude

6

Depuis, String est immuable en Java, les String gauche et droit doivent donc être copiés dans le nouveau String pour chaque paire de concaténation. Alors, mieux vaut opter pour l'espace réservé.


2
Ceci est correct s'il y a une seule paire, mais généralement incorrect, car le compilateur transforme la concaténation en appels de générateur de chaînes, ce qui entraîne un code beaucoup plus rapide qui ne fait pas autant d'allocation.
cdeszaq

3

Une autre alternative est String.format(). Nous l'utilisons dans jcabi-log (wrapper d'utilitaire statique autour de slf4j).

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

C'est beaucoup plus maintenable et extensible. De plus, c'est facile à traduire.


3
Je ne pense pas que ce soit plus facile à maintenir. si le type de valuechangement, vous devez revenir en arrière et modifier également l'instruction de journalisation. Quelque chose pour lequel les IDE ne vous aideront pas. Les enregistreurs doivent aider au débogage et ne pas y gêner. :-)
Chetan Narsude

3
@ChetanNarsude IntelliJ 2016 me dit au moins quand la chaîne de format ne correspond pas aux arguments de formatage. Par exemple: String.format("%d", "Test")produit l'avertissement IntelliJ Argument type 'String' does not match the type of the format specifier '%d'.. Cependant, je ne suis pas sûr qu'il serait toujours en mesure de fournir cette réponse intelligente en travaillant avec la solution ci-dessus.
écraser

quelle est la vitesse de ceci?
Thorbjørn Ravn Andersen

@ ThorbjørnRavnAndersen c'est assez primitif à l'intérieur, mais bien sûr, c'est plus lent qu'un enregistreur statique
yegor256

Emballage slf4j? cela ne va-t-il pas à l'encontre de l'objectif de l'utilisation de slf4j? De plus, j'ai vu de nombreuses personnes abuser de String.format de sorte que la chaîne soit formatée avant que le niveau de journalisation ne soit évalué, comme: logger.info (String.format ("bonjour% s", nom d'utilisateur)).
Juan Bustamante

2

Je pense que du point de vue de l'auteur, la raison principale est de réduire la surcharge pour la concaténation de chaînes.Je viens de lire la documentation de l'enregistreur, vous pouvez trouver les mots suivants:

/**
* <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);
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.