我正在阅读Java中的参数化日志记录,据说它在执行延迟评估时使用参数化日志记录而不是连接。
所以而不是
logger.debug("My text is" + x);
使用:
logger.debug("My text is {}", x);
如果跟踪级别仅设置为信息日志,为什么连接会在第一个场景中发生?
此外,如果我在日志中有耗时的功能,则说它使用:
logger.debug("My text is {}", () -> compute());
而不是
logger.debug("My text is {}", compute());
在这种情况下,为什么lambda方法被认为是更好的方法。不会像在字符串连接情况下一样被称为懒惰计算吗?
答案 0 :(得分:9)
在输入logger.debug()
之前,必须计算参数。
在第一种情况下,在将生成的String传递给方法(可能不使用它)之前,始终会获得字符串连接。使用参数化版本不会进行连接,x
将被传入并可以使用或不使用。
与compute()
相同的交易。在输入方法之前,非lambda版本将始终执行compute()
,因为它需要compute()
的结果才能调用该方法。
lambda版本将传递方法(实际上是Supplier
,它在请求结果时运行该方法)作为参数而不是方法结果,并且它只会被执行如果需要的话。
答案 1 :(得分:5)
这个想法很简单。通常,应用程序非常频繁地使用logger,但是日志记录本身是耗费资源的操作,至少因为您需要向硬盘驱动器写入内容。看看你的例子:
logger.debug("My text is " + x);
让我们假设在记录器配置中启用了INFO级别。然后代码执行这一行,它需要评估参数以传递debug
函数,所以它确实如此。但是在debug
内部记录器将检查打开的日志级别,它将是INFO。在这种情况下,不应记录您想要的消息,因此组装参数字符串所需的计算将被视为浪费时间。
要解决此类问题,您可以在调用方法之前检查日志级别是否已转换,如此
if (logger.isDebugEnabled()) {
logger.debug("My text is " + x)
}
它会更好,因为你只会收集消息,但这里的问题是logger.isDebugEnabled()
评估了两次。首先在代码中,然后在logger.debug()
内。
这就是参数化日志记录的原因,因为它将这两个问题都抛在了后面。
这同样适用于lambdas建议的耗时操作。希望现在对你有所帮助,有点清楚!
答案 2 :(得分:1)
这与Optional.orElse()
vs Optional.orElseGet()
几乎完全相同,第二个只在需要时调用。
我假设记录器在内部检查这样的事情:
if(logLevel.isDebug()){
Value v = supplier.get();
// log v
}
假设你的lambda使用了一些繁重的调用来计算这个值(比如DB call
),你肯定不会在需要的时候一直不想要计算 。