对于日志记录方法,哪个数组创建与字符串连接具有更好的性能?

传递多个字符串进行日志记录时,最好使用varargs还是字符串连接?

将在生产环境中禁用日志记录。

考虑以下代码,

public void log(int logLevel, String ... msg) { if (logLevel >= currentLogLevel) { for (String m : msg) { // print the log to file } } } // calling log(2, "text1", var1, "text2"); 

比。

 public void log(int logLevel, String msg) { if (logLevel >= currentLogLevel) { // print the log to file } } // calling log(2, "text1" + var1 + "text2"); 

哪一个在两种情况下都有效(启用/禁用)?

这些都不是特别好。 varargs会表现得更好,因为它不进行String连接,这是一个比数组创建更昂贵的操作,但是因为你使用的是String变量而不是Object变量,所以必须在所有String上调用toString()方法甚至在生产中的物品,这将是相对昂贵的。

但是,不要害怕! 这是一个已解决的问题 。 SLF4J(Java的简单日志外观)已经找到了为您完成此任务的最佳方法。 如果您使用SLF4J实现(最常见的两个是Log4J和Logback ),则可以使用参数化日志记录参数 :

更好的选择

存在基于消息格式的便利替代方案。 假设entry是一个对象,你可以写:

 Object entry = new SomeObject(); logger.debug("The entry is {}.", entry); 

只有在评估是否记录之后,并且只有在决策是肯定的情况下,记录器实现才会格式化消息并将“{}”对替换为条目的字符串值。 换句话说,当禁用日志语句时,此表单不会产生参数构造的成本。

以下两行将产生完全相同的输出。 但是,在禁用日志记录语句的情况下,第二个变体将比第一个变体优于至少30倍。

 logger.debug("The new entry is "+entry+"."); logger.debug("The new entry is {}.", entry); 

也可以使用两个参数变体。 例如,您可以写:

 logger.debug("The new entry is {}. It replaces {}.", entry, oldEntry); 

如果需要传递三个或更多参数,则还可以使用Object []变体。 例如,您可以写:

 Object[] paramArray = {newVal, below, above}; logger.debug("Value {} was inserted between {} and {}.", paramArray); 

请注意,在第一种情况和第二种情况下,它不会创建临时数组, 如果在SLF4J中不需要,则存在不创建数组的方法签名。 以下是完整的文档,您可以在其中查看所有不同的方法签名

如果您决定使用Logback ,您应该知道在关闭日志记录时方法调用的成本大约是20纳秒。 完整讨论Logback的性能 :

您可以通过将根记录器的级别设置为Level.OFF(可能的最高级别)来完全关闭日志记录。 完全关闭日志记录时,日志请求的成本包括方法调用和整数比较。 在3.2Ghz Pentium D机器上,此成本通常约为20纳秒。

从Java-8开始,使用Supplier有一个更快的替代方案:

 public void log(int logLevel, Supplier msg) { if (logLevel >= currentLogLevel) { // print the log to file like out.println(msg.get()); } } // calling log(2, () -> "text1" + var1 + "text2"); 

如果您多次执行此行,这比串联要快得多(第一次因为应该创建匿名类而慢)。 资料来源:AlekseyShipilëv 谈Joker’14 (PDF,查看幻灯片26-28)。

如果您使用的是SLF4J ,则可以执行参数化日志消息。 像这样

 log.info("Item {} is done, it took {} ms", item.getName(), duration); 

这也有好处,也不必将其中的一些包装在日志级别检查if(log.isDebugEnabled()) 。 看到这个常见问题