Логгер slf4j переваги форматування з {} замість конкатенації рядків


100

Чи є якась перевага використання {}замість об’єднання рядків?

Приклад із slf4j

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

замість

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

Я думаю, що мова йде про оптимізацію швидкості, оскільки оцінки параметрів (і конкатенації рядків) можна було б уникнути під час виконання, залежно від конфігураційного файлу. Але можливі лише два параметри, то іноді немає іншого вибору, крім об’єднання рядків. Потрібні думки з цього питання.

Відповіді:


74

Це є про продуктивність конкатенації. Це потенційно важливо, якщо у вас є щільні оператори реєстрації.

(До SLF4J 1.7) Але можливі лише два параметри

Оскільки переважна більшість операторів журналювання має 2 або менше параметрів, тому API SLF4J до версії 1.6 охоплює (лише) більшість випадків використання. Розробники API надають перевантажені методи з параметрами varargs, починаючи з версії API 1.7.

У тих випадках, коли вам потрібно більше 2, і ви застрягли в попередній версії 1.7 SLF4J, просто використовуйте або конкатенацію рядків, або new Object[] { param1, param2, param3, ... }. Їх має бути мало, щоб продуктивність була не такою важливою.


2
Слід уникати невикористаної конкатенації рядків (тобто операторів налагодження). Використовуйте або (надто багатослівний, але ефективний) перевірку на рівні журналу, або параметр масиву об’єкта (тонший, але, можливо, незначний). (Я віддав би перевагу останньому, за всіх рівних умов.) Важко сказати, що рядок concat не буде важливим / не вплине на продуктивність. Створення об'єктного масиву теоретично могло б бути вбудованим та оптимізованим, і "насправді" не матиме значення (проти бажаного мислення). (Це не передчасна оптимізація, це просто питання зробити щось правильно / краще з першого разу.)
Майкл

чому не виконуються перевантажені модифікації, щоб System.out.println () слідував подібно до реєстратора slf4j, щоб він уникав конкатенації рядків?
a3.14_Бесконечність

44

Коротка версія: Так, це швидше, з меншим кодом!

Конкатенація рядків робить багато роботи, не знаючи, потрібна вона чи ні (традиційний тест "увімкнено налагодження", відомий з log4j), і його слід уникати, якщо це можливо, оскільки {} дозволяє затримувати виклик toString () та побудову рядків до того, як буде вирішено, чи потрібно подію фіксувати чи ні. На мою думку, формат реєстратора єдиного рядка код стає чистішим.

Ви можете надати будь-яку кількість аргументів. Зверніть увагу, що якщо ви використовуєте стару версію sljf4j і у вас є більше двох аргументів {}, ви повинні використовувати new Object[]{a,b,c,d}синтаксис для передачі масиву. Див., Наприклад, http://slf4j.org/apidocs/org/slf4j/Logger.html#debug(java.lang.String, java.lang.Object []) .

Щодо швидкості: Чекі опублікував контрольний показник ще в одному зі списків.


6
Примітка: останні Javadoc показує новий синтаксис вар-Arg, debug(String format, Object... arguments). Дивіться slf4j.org/faq.html#logging_performance
Майкл

Проголосував за згадку про оцінку .toString () на додаток до продуктивності конкатенації. Це те, що відбувається всередині реєстратора, і реєстратор може вирішити, чи потрібно викликати цей метод. Це не відбувається, якщо рядок рівня реєстрації не виконується.
Четан Нарсуде

6

Оскільки String є незмінним у Java, тому лівий та правий String повинні бути скопійовані в новий String для кожної пари конкатенації. Отже, краще йти на заповнювач.


2
Це правильно, якщо є одна пара, але, як правило, неправильно, оскільки компілятор перетворює конкатенацію у виклики конструктора рядків, що призводить до набагато швидшого коду, який не робить стільки виділення.
cdeszaq

3

Іншою альтернативою є String.format(). Ми використовуємо його в jcabi-log (статична оболонка утиліти навколо slf4j).

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

Це набагато зручніше для обслуговування та розширення. До того ж це легко перекласти.


3
Я не думаю, що це більш ремонтопридатне. якщо тип valueзмін, вам доведеться повернутися назад і також змінити оператор журналу. Щось, у чому IDE не допоможуть вам. Лісоруби повинні допомагати з налагодженням і не заважати цьому. :-)
Четан Нарсуде

3
@ChetanNarsude IntelliJ 2016 принаймні повідомляє мені, коли рядок формату не відповідає аргументам форматування. Наприклад: String.format("%d", "Test")видає попередження IntelliJ Argument type 'String' does not match the type of the format specifier '%d'.. Хоча, я не впевнений, що він все одно зможе надати цю розумну відповідь при роботі з вищезазначеним рішенням.
розчавити

яка швидкість цього?
Торбьорн Равн Андерсен

@ ThorbjørnRavnAndersen це досить примітивно всередині, але, звичайно, це повільніше, ніж статичний реєстратор
yegor256

Обгортання slf4j? хіба це не перемагає мети використання slf4j? Крім того, я бачив, як багато людей неправильно використовують String.format, так що рядок форматується перед оцінкою рівня журналу, наприклад: logger.info (String.format ("привіт% s", ім'я користувача)).
Хуан Бустаманте,

2

Я думаю, що з точки зору автора, основною причиною є зменшення накладних витрат на конкатенацію рядків. Я просто прочитав документацію реєстратора, ви можете знайти такі слова:

/**
* <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);
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.