Logger slf4j 使用 {} 格式化而不是字符串连接的优点

问题描述 投票:0回答:7

使用

{}
代替字符串连接有什么优势吗?

来自 slf4j 的示例

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

而不是

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

我认为这与速度优化有关,因为根据配置文件,可以在运行时避免参数评估(和字符串连接)。但只有两个参数是可能的,那么有时除了字符串连接之外别无选择。需要对此问题的看法。

optimization logging concatenation string-formatting slf4j
7个回答
91
投票

是关于字符串连接性能的。如果您有密集的日志记录语句,这可能很重要。

(SLF4J 1.7之前)但只能使用两个参数

由于绝大多数日志记录语句都有 2 个或更少的参数,因此 SLF4J API 至版本 1.6 涵盖(仅)大多数用例。自 API 1.7 版本以来,API 设计者提供了带有可变参数参数的重载方法。

对于需要超过 2 个并且您受困于 1.7 之前的 SLF4J 的情况,则只需使用字符串连接或

new Object[] { param1, param2, param3, ... }
。它们的数量应该足够少,性能就不那么重要了。


63
投票

简短版本:是的,速度更快,代码更少!

字符串连接在不知道是否需要的情况下做了很多工作(log4j 中已知的传统“启用调试”测试),并且应该尽可能避免,因为 {} 允许延迟 toString() 调用和字符串确定事件是否需要捕获后进行构建。在我看来,通过让记录器格式化一个single字符串,代码会变得更干净。

您可以提供任意数量的参数。请注意,如果您使用旧版本的 sljf4j 并且有两个以上的

{}
参数,则必须使用
new Object[]{a,b,c,d}
语法来传递数组。参见例如http://slf4j.org/apidocs/org/slf4j/Logger.html#debug(java.lang.String, java.lang.Object[]).

关于速度:Ceki 不久前在其中一个列表上发布了一个基准。


8
投票

由于 String 在 Java 中是不可变的,因此对于每对串联,必须将左右 String 复制到新 String 中。所以,最好选择占位符。


3
投票

另一种选择是

String.format()
。我们在 jcabi-log(围绕 slf4j 的静态实用程序包装器)中使用它。

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

它更易于维护和扩展。此外,它很容易翻译。


2
投票

我认为从作者的角度来看,主要原因是为了减少字符串连接的开销。我刚刚阅读了logger的文档,你可以找到以下文字:

/**
* <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);

1
投票

串联的成本很高,因此您希望仅在需要时才进行串联。通过使用

{}
,slf4j 仅在需要跟踪时才执行串联。在生产中,您可以将日志级别配置为 INFO,从而忽略所有调试跟踪。

这样的跟踪将连接字符串,即使跟踪将被忽略,这是浪费时间:

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

这样的痕迹将被免费忽略:

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

如果您有很多在生产中忽略的调试跟踪,那么使用

{}
肯定更好,因为它对性能没有影响。


0
投票

合规日志记录对于应用程序开发非常重要,因为它会影响性能。

提到的不合规日志记录会在每次调用时导致冗余的 toString() 方法调用,并导致冗余的临时内存分配和 CPU 处理,如大规模测试执行示例所示,我们可以在其中采取查看冗余分配的临时内存: Memory

查看方法分析:
Look on method profiling

注意:我是这篇博文的作者,记录对应用程序性能的影响

© www.soinside.com 2019 - 2024. All rights reserved.