Log4j2使用{}和使用%d或%s的区别

23
在Log4j2中,以下两种方式是否同样高效且不会在日志级别比DEBUG更特定的情况下引起任何字符串连接?是否有任何原因/情况使其中一种方式优于另一种?
log.warn(String.format("Number of cars : %d",carCount));
log.warn("Number of cars : {}",carCount );

{} 能够适用于任何类型的对象吗?


1
现在有了单独的String.format,那么它不是总会被调用吗?尽管仍然对原始问题感到好奇。 - Marvin
我肯定推荐使用第二种方法,因为它不依赖于类型。例如,对于第一种方法,如果您将字符串传递给十进制参数(例如%d),则可能会收到异常。@BoristheSpider更正了评论。 - Darshan Mehta
@Andy897 不,只有在特殊情况下才应该使用 FomatterLogger。它硬编码了日志格式,并可能导致昂贵的方法被急切地调用(除非与 Java 8 Supplier 公式 一起使用)。最好使用简单的 {} 格式,并且只传递方法调用的引用,而不是调用方法的结果。 - Boris the Spider
评论不适合进行长时间的讨论;此对话已被移至聊天室 - Bhargav Rao
1个回答

49

使用{}表示法比%s %d字符串格式化表示法更有效率。(这方面有基准测试数据,稍后我会添加一些数字。)

{}表示法接受任何对象或基本类型值,而%s %d ...字符串格式化则要求参数的类型与格式匹配,否则将抛出异常。因此,{}通常更加方便。

但有些情况下,您可能想要使用字符串格式化语法,因为它可以对格式进行非常精细的控制。例如,如果您想要将一个大数字“漂亮地打印”成1,234,567.123,或者控制小数点后的位数,则{}不足以实现。

Log4j2允许混合使用两种表示法。您可以在所有地方都使用字符串格式化语法(通过使用LogManager.getFormattedLogger),但使用默认的{}格式大部分时间更方便,只需要在需要使用printf方法进行精细控制时才使用字符串格式化语法。

logger.printf(Level.INFO, "Logging in user %1$s with birthday %2$tm %2$te,%2$tY", user.getName(), user.getBirthdayCalendar());

在内部,使用 {} 格式,Log4j2 尽力避免创建字符串或其他临时对象。这在使用字符串格式语法时是不可能的。


1
非常感谢Remko提供如此详细的回答。只有一个快速的问题。在任何情况下,使用{}会抛出运行时异常吗? - Andy897
这可能不是一个恰当的地方来询问或说这件事......但您能否建议我如何跟进此问题 - https://issues.apache.org/jira/browse/LOG4J2-1768 。我的跟进至少意味着确认问题是否存在 :) - Andy897
2
默认情况下,Log4j会吞噬异常。您可以通过设置ignoreExceptions="false"来配置每个Appender将异常传播给调用者。请参阅appender文档。 - Remko Popma
1
好的。但是通常来说,将异常传播给调用者是一个好的做法吗?还是应该让Log4j来处理呢? - Andy897
1
异常意味着您的日志语句未被记录。对于未满足要求的审计日志记录而言,这是一个问题。对于调试日志记录,您可能不希望中断应用程序的业务逻辑...因此,这取决于您想要什么。 - Remko Popma
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接