Lambda 程序中的應(yīng)用
通過(guò)前面的內(nèi)容我們對(duì)于 Lambda 表達(dá)式以及函數(shù)式編程已經(jīng)有了一定的了解,對(duì)于集合方面的使用也有了概念,那么,在本節(jié)我們將從一個(gè)日志改造的例子出發(fā),探討下如何在我們的程序中更好地使用 Lambda 表達(dá)式。
Tips: 本節(jié)內(nèi)容有點(diǎn)分散,主要是啟發(fā)大家的思路
1. 讓我們的類(lèi)支持 Lambda 表達(dá)式
日志記錄工具是我們平時(shí)用的最多的一個(gè)工具,比如 SLF4J、Log4j 等,可以幫助我們快速查看程序的信息、定位問(wèn)題,也在一定程度上增加了系統(tǒng)開(kāi)銷(xiāo),通常我們?cè)趯?xiě) debug
日志的時(shí)候?yàn)榱私档蜁?huì)進(jìn)行日志級(jí)別的判定 (在本例中我們使用的是 Log4j 2)
public class DemoLogger {
public static void main(String[] args) {
Logger logger = LogManager.getLogger(DemoLogger.class);
if(logger.isDebugEnabled()){
logger.debug("這是一個(gè)debug日志");
}
}
}
想必上面的代碼應(yīng)該都非常熟悉,在 Log4j 2 中提供了 Lambda 表達(dá)式實(shí)現(xiàn)的日志記錄方法,對(duì)于上述代碼我們可以簡(jiǎn)化為:
public class DemoLogger {
public static void main(String[] args) {
Logger logger = LogManager.getLogger(DemoLogger.class);
logger.debug(()->"這是一個(gè)debug日志");
}
}
通過(guò)查看源代碼我們可以發(fā)現(xiàn) Logger 對(duì)象提供了一個(gè) Supplier 的 debug
方法:
@Override
public void debug(final Supplier<?> msgSupplier) {
logIfEnabled(FQCN, Level.DEBUG, null, msgSupplier, (Throwable) null);
}
@Override
public void logIfEnabled(final String fqcn, final Level level, final Marker marker, final Supplier<?> msgSupplier,
final Throwable t) {
if (isEnabled(level, marker, msgSupplier, t)) {
logMessage(fqcn, level, marker, msgSupplier, t);
}
}
在這個(gè)方法中,它通過(guò) logIfEnabled
判斷是否為 debug
進(jìn)而決定是否調(diào)用 supplier
對(duì)象的內(nèi)容。 這給了我們一個(gè)啟發(fā),那就是:
我們可以運(yùn)用
java.util.funciton
中的接口來(lái)重新封裝我們?cè)械念?lèi)來(lái)支持 Lambda 表達(dá)式,進(jìn)而簡(jiǎn)化我們的代碼。
2. 多重繼承
在 Java 中接口是允許多重繼承的,那么如果多個(gè)接口有著相同的默認(rèn)方法的情況下會(huì)怎么樣呢?
public class MultipleInterface {
public interface RedBox{
public default String color(){
return "red";
}
}
public interface BlueBox{
public default String color(){
return "blue";
}
}
public class CombineBox implements RedBox,BlueBox{
}
}
在上面的代碼中,我們定義了兩個(gè)接口 RedBox
和 BlueBox
都有相同的默認(rèn)方法 color
,類(lèi) CombineBox
同時(shí)實(shí)現(xiàn) RedBox
和 BlueBox
,此時(shí),由于編譯器不清楚應(yīng)該繼承哪個(gè)接口,所以報(bào)錯(cuò):
MultipleInterface.CombineBox inherits unrelated defaults for color() from types MultipleInterface.RedBox and MultipleInterface.BlueBox
此時(shí),我們可以使用同方法重載來(lái)明確方法內(nèi)容,當(dāng)然我們可以通過(guò) super
語(yǔ)法來(lái)給編譯器明確使用哪一個(gè)默認(rèn)接口:
public class CombineBox implements RedBox,BlueBox{
public String color(){
return RedBox.super.color();
}
}
上述的內(nèi)容我們主要是對(duì)默認(rèn)方法的工作原理做了一個(gè)簡(jiǎn)單的介紹,對(duì)于默認(rèn)方法通常有三條定律來(lái)幫助我們使用默認(rèn)方法:
- 類(lèi)勝于接口:如果在繼承鏈中有聲明的方法,那么就可以忽略接口中定義的方法 (這樣可以讓我們的代碼向后兼容);
- 子類(lèi)勝于父類(lèi):如果一個(gè)接口繼承了另外一個(gè)接口,而且兩個(gè)接口都定義了一個(gè)默認(rèn)方法,那么子類(lèi)中定義的方法將生效;
- 如果上述兩條都不適用,那么子類(lèi)要么需要實(shí)現(xiàn)該方法,要么將該方法聲明成抽象方法 (
abstract
)。
小結(jié)

本節(jié)從類(lèi)的重新和接口繼承兩方面介紹了我們?nèi)绾沃匦路庋b我們的類(lèi)來(lái)支持 Lambda 表達(dá)式,以及在函數(shù)接口在多繼承的情況下出現(xiàn)默認(rèn)方法沖突時(shí)如何去編寫(xiě)我們的代碼。大家可以在平時(shí)的編碼過(guò)程中按照上述的思路逐步練習(xí)封裝自己原來(lái)的代碼,自然就會(huì)有自己的心得體會(huì)。