20

在 log4j 中,如果我们写

**logger.debug("Processing trade with id: " + id + " symbol: " + symbol);**

它将在字符串池中创建字符串,但是当我们使用 slf4j 时,我们使用基于这样的参数

**logger.debug("Processing trade with id: {} and symbol : {} ", id, symbol);**

那么这两个语句有什么区别,slf4j 是否会在运行时创建 String 呢?

4

6 回答 6

23

不同之处在于性能的提高,在 log4j 中,即使日志级别低于调试,每次评估行时都会连接字符串,因此永远不会使用该字符串。

slf4j,字符串和参数被传递给记录器,只有在实际使用日志消息时才会替换它们。

想象一下每隔几行带有调试语句的代码,当在生产和调试被禁用时,这是永远不会使用的大量字符串操作。

于 2014-04-25T09:52:58.430 回答
7

SLF4J 基本上是一个抽象层。它不是日志记录实现。这意味着如果您正在编写一个库并使用 SLF4J,您可以将该库提供给其他人使用,他们可以选择使用 SLF4J 的日志记录实现,例如 log4j 或 Java 日志记录 API。它有助于防止项目仅仅因为它们使用依赖于它们的库而依赖于大量日志记录 API。

于 2014-09-30T10:02:33.677 回答
7

我会说通过减少 String 来提高性能concatenations

当你写这个

"Processing trade with id: " + id + " symbol: " + symbol

您正在手动创建打印字符串。

当你写

"Processing trade with id: {} and symbol : {} ", id, symbol
                    -------^id------------^symbol---------

在打印之前的第二种方式在内部slf4j维护并再次使用连接生成一个新字符串(没有检查源代码,可能是a StringBuilder)。

{} 称为占位符并替换为您传递的参数。

来自 sl4j 的文档

当记录器在调试级别被禁用时,这种形式避免了多余的字符串连接。但是,此变体在调用该方法之前会产生隐藏的(且相对较小的)成本,即使此记录器已针对 DEBUG 禁用也是如此。采用一个和两个参数的变体只是为了避免这种隐藏成本而存在。

阅读如何使用格式:如何在 Scala 中使用 java.String.format?

于 2013-10-09T11:30:39.403 回答
2

使用 Log4j2 API,我们可以拥有 logger.info("String: {} int : {}.", "Hello, World ", 10);

于 2016-03-28T06:34:09.650 回答
1

那么这两个语句有什么区别,slf4j 是否会在朗姆酒时间创建字符串?

无论您使用 log4j 还是 sl4j,无论如何都会创建字符串。sl4j 提供了方便的占位符。

于 2013-10-09T11:32:30.873 回答
0

它是关于字符串连接的。第一行总是使字符串连接那个昂贵的操作,如果日志级别不匹配调试,第二行不是连接。我不确定只是假设,由于内部 StringBuilder 的使用,匹配日志级别的第二个选项可以提高性能。

于 2013-10-09T11:32:36.770 回答