Java Lambda 表达式和日志记录

Java Lambda Expression and Logging

我正在阅读 Log4j2 的新特性,有一个特性可以启用

"Java 8 lambda support for lazy logging"

并给出了两个例子

第一个是不好的做法

// pre-Java 8 style optimization: explicitly check the log level
// to make sure the expensiveOperation() method is only called if necessary
 if (logger.isTraceEnabled()) {
  logger.trace("Some long-running operation returned {}", expensiveOperation());
 }

第二个是好的做法

// Java-8 style optimization: no need to explicitly check the log level:
// the lambda expression is not evaluated if the TRACE level is not enabled
logger.trace("Some long-running operation returned {}", () -> expensiveOperation());

在哪里检查请求的日志级别是否已启用? "logger.isTraceEnabled()" ?

Where is being made the checking if the requested log level is enabled ?

logger.trace() 方法中。

这里的技巧在于你传递参数的方式。 Pre-java8 样式计算调用时的值 logger.trace.

logger.trace(..., expensiveOperation());

Java 8个样式用了一个Supplier

logger.trace( ..., () -> expensiveOperation());

因此 expensiveOperation() 仅在请求时调用 - 在 trace 方法中。

查看 java.util.logging.Logger.log() 的实现:

public void log(Level level, Supplier<String> msgSupplier) {
    if (!isLoggable(level)) {
        return;
    }
    LogRecord lr = new LogRecord(level, msgSupplier.get()); // <-- here is the expensive computation
    doLog(lr);
}

trace 方法(或为此目的的任何其他日志记录方法)已经在内部检查日志记录级别。在调用者中检查它也是一种避免计算 expensiveOperation() 的优化。使用 Java 8 的新语法,我们不会传递 expensiveOperation() 的计算值,而是仅在需要时调用它的 lambda。

请注意,虽然 log4j 没有实现它,但理论上,您可以通过为值提供程序定义一个接口并调用日志记录方法来获得相同的行为,而无需花哨的 Java8 语法它:

// Interface definition
public interface ValueProvider {
    String getValue();
}

// Calling it from the main code with an anonymous implementation:
logger.trace("Some long-running operation returned {}",
             new ValueProvider() {
                 public String getValue() {
                     return expensiveOperation();
                 }
             });