Java 利用Supplier创建日志消息,用户希望创建由日志级别(log level)控制是否可见的日志消息。使用 java.util.logging.Logger
类新增的各种日志方法,它们传入 Supplier
作为参数。目前,Logger
类中的日志方法(如 info
、warning
、severe
等)包括两种重载形式,一种传入单个 String
作为参数,另一种传入 Supplier<String>
作为参数。
Java 利用Supplier创建日志消息 问题描述
用户希望创建由日志级别(log level)控制是否可见的日志消息。
Java 利用Supplier创建日志消息 解决方案
使用 java.util.logging.Logger
类新增的各种日志方法,它们传入 Supplier
作为参数。
Java 利用Supplier创建日志消息 具体实例
目前,Logger
类中的日志方法(如 info
、warning
、severe
等)包括两种重载形式,一种传入单个 String
作为参数,另一种传入 Supplier<String>
作为参数。
例 5-20 显示了各种日志方法的签名。7
7读者或许奇怪,Java 日志框架的设计者为什么不采用与其他日志 API 相同的日志级别(Trace、Debug、Info、Warn、Error、Fatal)。这是一个非常好的问题,如果读者找到答案,也请告诉作者。
例 5-20
Logger
类中各种日志方法的重载形式
void fine(String msg)
void fine(Supplier<String> msgSupplier)
void finer(String msg)
void finer(Supplier<String> msgSupplier)
void finest(String msg)
void finest(Supplier<String> msgSupplier)
void info(String msg)
void info(Supplier<String> msgSupplier)
void warning(String msg)
void warning(Supplier<String> msgSupplier)
void severe(String msg)
void severe(Supplier<String> msgSupplier)
每种方法的第一种重载形式(传入 String
)是 Java 1.4 引入的,而第二种重载形式(传入 Supplier
)是 Java 8 引入的,它在标准库中的实现如例 5-21 所示。
例 5-21
Logger
类的实现细节
public void info(Supplier<String> msgSupplier) {
log(Level.INFO, msgSupplier);
}
public void log(Level level, Supplier<String> msgSupplier) {
if (!isLoggable(level)) { ➊
return;
}
LogRecord lr = new LogRecord(level, msgSupplier.get()); ➋
doLog(lr);
}
❶ 如果不显示消息则返回
❷ 调用 get
方法以便在 Supplier
中检索消息
上述实现并非构建一个永远不会显示的消息,而是检查消息是否是“可记录的”(loggable)。如果所提供的消息是一个简单的字符串,程序将评估它是否已被记录。在上述日志方法中,第二种重载形式(传入 Supplier
)支持在消息前添加空括号和箭头(() ->
)以将其转换为 Supplier
,且仅当日志级别合适时才会调用它。例 5-22 显示了 info
方法的两种重载形式。
例 5-22 在
info
方法中使用Supplier
private Logger logger = Logger.getLogger(this.getClass().getName());
private List<String> data = new ArrayList<>();
// 用数据填充列表
logger.info("The data is " + data.toString()); ➊
logger.info(() -> "The data is " + data.toString()); ➋
❶ 无论是否显示 Info 消息,都会构建参数
❷ 仅当日志级别显示 Info 消息时,才会构建参数
可以看到,消息在列表的每个对象上调用 toString
方法。在第一条 logger.info
语句中,无论程序是否显示 Info 消息,都会创建结果字符串;在第二条 logger.info
语句中,在消息前添加 () ->
就能将日志参数转换为 Supplier
,这意味着只有使用消息时才会调用 Supplier
的 get
方法。
采用相同类型的 Supplier
替换参数的技术称为延迟执行(deferred execution),可以在任何对象创建成本较高的上下文中使用。