Logger slf4j vantaggi della formattazione con {} invece della concatenazione di stringhe


100

C'è qualche vantaggio nell'usare {}invece della concatenazione di stringhe?

Un esempio da slf4j

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

invece di

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

Penso che si tratti di ottimizzazione della velocità perché la valutazione dei parametri (e la concatenazione di stringhe) potrebbe essere evitata in runtime a seconda di un file di configurazione. Ma sono possibili solo due parametri, quindi a volte non c'è altra scelta che la concatenazione di stringhe. Avendo bisogno di opinioni su questo problema.

Risposte:


74

Si tratta di prestazioni di concatenazione di stringhe. È potenzialmente significativo se hai dichiarazioni di registrazione dense.

(Prima di SLF4J 1.7) Ma sono possibili solo due parametri

Poiché la stragrande maggioranza delle istruzioni di registrazione ha 2 o meno parametri, l'API SLF4J fino alla versione 1.6 copre (solo) la maggior parte dei casi d'uso. I progettisti API hanno fornito metodi sovraccaricati con parametri varargs dalla versione 1.7 dell'API.

Per quei casi in cui hai bisogno di più di 2 e sei bloccato con SLF4J pre-1.7, usa semplicemente la concatenazione di stringhe o new Object[] { param1, param2, param3, ... }. Dovrebbero essercene abbastanza pochi perché le prestazioni non siano così importanti.


2
La concatenazione di stringhe inutilizzata (cioè le istruzioni di debug) dovrebbe essere evitata. Utilizzare il controllo a livello di registro (eccessivamente dettagliato ma efficiente) o il parametro dell'array di oggetti (più sottile, ma forse minore). (Preferirei il secondo, a parità di condizioni.) È difficile dire che il concatenamento di stringhe non sarà importante / non influirà sulle prestazioni. La creazione di array di oggetti potrebbe in teoria essere integrata e ottimizzata e "davvero" non fare la differenza (rispetto a un pio desiderio). (Non è un'ottimizzazione prematura, è semplicemente una questione di fare qualcosa di giusto / migliore la prima volta.)
michael

perché le modifiche sovraccaricate non vengono eseguite per System.out.println () in modo simile al logger di slf4j, in modo che eviti la concatenazione di stringhe?
a3.14_Infinity

45

Versione breve: Sì, è più veloce, con meno codice!

La concatenazione di stringhe fa molto lavoro senza sapere se è necessaria o meno (il tradizionale test "è abilitato al debug" noto da log4j) e dovrebbe essere evitata se possibile, poiché {} consente di ritardare la chiamata a toString () e la costruzione di stringhe dopo che è stato deciso se l'evento deve essere catturato o meno. Avendo il logger in formato una singola stringa, il codice diventa più pulito secondo me.

Puoi fornire un numero qualsiasi di argomenti. Nota che se usi una vecchia versione di sljf4j e hai più di due argomenti {}, devi invece usare la new Object[]{a,b,c,d}sintassi per passare un array. Vedi ad esempio http://slf4j.org/apidocs/org/slf4j/Logger.html#debug(java.lang.String, java.lang.Object []) .

Per quanto riguarda la velocità: Ceki ha pubblicato un benchmark qualche tempo fa in una delle liste.


6
Nota: le ultime Javadoc mostra la sintassi var-arg più recente, debug(String format, Object... arguments). Vedi slf4j.org/faq.html#logging_performance
michael

Votato per la menzione della valutazione .toString () oltre alle prestazioni di concatenazione. Questo è qualcosa che accade all'interno del logger e il logger può decidere se è necessario invocare quel metodo. Non lo fa se la barra del livello di registrazione non è soddisfatta.
Chetan Narsude

6

Poiché, String è immutabile in Java, quindi la stringa sinistra e destra devono essere copiate nella nuova stringa per ogni coppia di concatenazioni. Quindi, meglio andare per il segnaposto.


2
Questo è corretto se c'è una singola coppia, ma generalmente non è corretto, poiché il compilatore trasforma la concatenazione in chiamate al generatore di stringhe, risultando in codice molto più veloce che non esegue la stessa allocazione.
cdeszaq

3

Un'altra alternativa è String.format(). Lo stiamo usando in jcabi-log (wrapper di utilità statica attorno a slf4j).

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

È molto più manutenibile ed estendibile. Inoltre, è facile da tradurre.


3
Non credo sia più manutenibile. se il tipo di valuemodifiche, è necessario tornare indietro e modificare anche l'istruzione di registrazione. Qualcosa con cui gli IDE non ti aiuteranno. I logger dovrebbero aiutare con il debug e non intralciarlo. :-)
Chetan Narsude

3
@ChetanNarsude IntelliJ 2016 almeno mi dice quando la stringa di formato non si adatta agli argomenti di formattazione. Ad esempio: String.format("%d", "Test")produce l'avviso IntelliJ Argument type 'String' does not match the type of the format specifier '%d'.. Tuttavia, non sono sicuro che sarebbe ancora in grado di fornire questa risposta intelligente quando si lavora con la soluzione di cui sopra.
schiacciare

qual è la velocità di questo?
Thorbjørn Ravn Andersen

@ ThorbjørnRavnAndersen è piuttosto primitivo dentro, ma ovviamente è più lento di un logger statico
yegor256

Wrapping slf4j? non sconfigge lo scopo dell'utilizzo di slf4j? Inoltre, ho visto molte persone abusare di String.format in modo tale che la stringa venga formattata prima che il livello di log venga valutato, come: logger.info (String.format ("hello% s", username)).
Juan Bustamante

2

Penso che dal punto di vista dell'autore, il motivo principale sia ridurre l'overhead per la concatenazione di stringhe, ho appena letto la documentazione del logger, potresti trovare le seguenti parole:

/**
* <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);
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.