4.1 在代码中使用Lambda表达式
2.5节介绍了如何赋予Lambda表达式函数接口的类型,以及该类型的推导方式。从调用Lambda表达式的代码的角度来看,它和调用一个普通接口方法没什么区别。
让我们来看一个日志系统中的具体案例。在slf4j和log4j等几种常用的日志系统中,有一些记录日志的方法,当日志级别不低于某个固定级别时就会开始记录日志。如此一来,在日志框架中设置类似void debug(String message)这样的方法,当级别为debug时,它们就开始记录日志消息。
问题在于,频繁计算消息是否应该记录日志会对系统性能产生影响。程序员通过显式调用isDebugEnabled方法来优化系统性能,如例4-1所示。即使直接调用debug方法能省去记录文本信息,也仍然需要调用expensiveOperation方法,并且需要将执行结果和已有字符串连接起来,因此,使用if语句显式判断,可以让程序跑得更快。
例4-1 使用isDebugEnabled方法降低日志性能开销
Logger logger = new Logger();if (logger.isDebugEnabled()) {logger.debug("Look at this: " + expensiveOperation());}
这里我们想做的是传入一个Lambda表达式,生成一条用作日志信息的字符串。只有日志级别在调试或以上级别时,才会执行该Lambda表达式。使用这个方式重写上面的代码,如例4-2所示:
例4-2 使用Lambda表达式简化日志代码
Logger logger = new Logger();logger.debug(() -> "Look at this: " + expensiveOperation());
那么在Logger类中该方法是如何实现的呢?从类库的角度看,我们可以使用内置的Supplier函数接口,它只有一个get方法。然后通过调用isDebugEnabled判断是否需要记录日志,是否需要调用get方法,如果需要,就调用get方法并将结果传给debug方法。由此产生的代码如例4-3所示。
例4-3 启用Lambda表达式实现的日志记录器
public void debug(Supplier<String> message) {if (isDebugEnabled()) {debug(message.get());}}
调用get()方法,相当于调用传入的Lambda表达式。这种方式也能和匿名内部类一起工作,如果用户暂时无法升级到Java 8,这种方式可以实现向后兼容。
值得注意的是,不同的函数接口有不同的方法。如果使用Predicate,就应该调用test方法,如果使用Function,就应该调用apply方法。
