JAVA基礎(五)函數式接口-複用,解耦之利刃

Java極客  |  做者  /  鏗然一葉
這是Java極客的第 67 篇原創文章

相關閱讀:java

JAVA基礎(一)簡單、透徹理解內部類和靜態內部類
JAVA基礎(二)內存優化-使用Java引用作緩存
JAVA基礎(三)ClassLoader實現熱加載
JAVA基礎(四)枚舉(enum)和常量定義,工廠類使用對比
JAVA編程思想(一)經過依賴注入增長擴展性
JAVA編程思想(二)如何面向接口編程
JAVA編程思想(三)去掉彆扭的if,自注冊策略模式優雅知足開閉原則
JAVA編程思想(四)Builder模式經典範式以及和工廠模式如何選?
HikariPool源碼(二)設計思想借鑑
人在職場(一)IT大廠生存法則編程


1. 函數式接口

接口中只有一個抽象方法的接口稱爲函數式接口。函數式接口能夠經過@FunctionalInterface註解來修飾,也能夠不使用該註解,只要接口只有一個抽象方法則可。緩存

2. 函數式接口使用例子

2.1. 服務和消費者

import java.util.function.Consumer;

public class Service {
    // 方法入參爲函數式接口,函數定義爲消費Event
    public void exec(Consumer<Event> consumer) {
        Event event = new Event(1001, "get data from cache.");
        consumer.accept(event);
    }
}

// event通知消費類,消費event的方式是將event發出去
public class EventNotify {
    // 方法名並不重要,不須要和函數式接口方法名一致,只要參數和返回值一致則可
    public void send(Event event) {
        System.out.println("send event: " + event.toString());
    }
}

// event記錄消費類,消費event的方式是將event記錄下來
public class EventLogger {
    // 方法名並不重要,不須要和函數式接口方法名一致,只要參數和返回值一致則可
    public static void log(Event event) {
        System.out.println("log event: " + event.toString());
    }
}

public class Event {
    private int eventId;
    private String content;

    public Event(int eventId, String content) {
        this.eventId = eventId;
        this.content = content;
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append("eventId=").append(eventId).append(", ");
        builder.append("content=").append(content);
        return builder.toString();
    }

}
複製代碼

2.2. 使用函數式接口

public class FunctionDemo {
    public static void main(String[] args) {
        Service service = new Service();
        EventNotify eventNotify = new EventNotify();

        // 使用類實例::方法名傳入函數,這裏必須使用類實例,是由於這個方法聲明爲非靜態方法
        service.exec(eventNotify::send);

        // 使用類::方法名傳入函數,這裏可使用類而非類實例,是由於這個方法聲明爲靜態方法
        service.exec(EventLogger::log);
    }
}
複製代碼

輸出:app

send event: eventId=1001, content=get data from cache.
log event: eventId=1001, content=get data from cache.
複製代碼

看到這裏,不少人會想,從這個例子看,函數式接口並無什麼優點,不用函數式接口,使用接口實現類也能實現啊.ide

2.3. 不用函數式接口實現例子

2.3.1. 消費者直接實現接口方法

class NonFunctionEventNotify<Event> implements Consumer<Event> {
    @Override
    public void accept(Event event) {
        System.out.println("send event: " + event.toString());
    }
}

// 事件記錄類,消費event的方式是將event記錄下來
class NonFunctionEventLogger<Event> implements Consumer<Event> {
    @Override
    public void accept(Event event) {
        System.out.println("log event: " + event.toString());
    }
}
複製代碼

2.3.2. 使用接口實現類

public class FunctionDemo {
    public static void main(String[] args) {
        Service service = new Service();
        NonFunctionEventNotify nonFunctionEventNotify = new NonFunctionEventNotify();
        // 傳入實現類實例
        service.exec(nonFunctionEventNotify);

        NonFunctionEventLogger nonFunctionEventLogger = new NonFunctionEventLogger();
        // 傳入實現類實例
        service.exec(nonFunctionEventLogger);
    }
}
複製代碼

可見,不用函數式接口也能實現對應功能,那爲啥還要使用函數式接口呢函數

2.3.2. 函數式接口和接口實現方式差別以及優勢

差別以下:post

實現方式 摻入參數 實現接口 方法名
函數式接口 可直接傳入靜態方法,省去類實例化動做 不須要實現任何接口 沒有要求,只要方法入參和出參同樣則可
接口實現類 必須有類實例,傳入類實例的方法 須要實現指定接口 必須同接口方法徹底同樣

經過對比,函數式接口的優點就大大致現出來了。優化

  1. 方法入參到方法級,粒度比類小,這樣自由度更高,更靈活,就比如拼樂高,零件粒度越小,越能充分發揮想象力,進行自由組合。
  2. 不要求必須實現某個接口,對方法名也沒有要求,只要知足函數接口的入參和出參定義就行,這樣已有的代碼可能不用修改就能被利用,特別是當你手裏沒有源碼可改時這點顯得尤其重要(雖然能夠寫個包裝類去作適配,但能不寫不是更好麼

3. 總結

  1. 函數式接口能夠作到方法級複用,自由度更高,更靈活
  2. 函數式接口的方法定義和調用者實現方法定義解耦,不須要方法一致,也不要求實現該接口。
  3. 方法定義解耦後,只要方法的入參和出參一致時,就能夠複用已有代碼,避免修改,複用性大大提升。

注:Java提供的函數式接口已經能知足大部分使用場景,這些接口能夠在java.util.function包下找到。ui

end.this


<--閱過留痕,左邊點贊!

相關文章
相關標籤/搜索