[徹底理解]JDK1.8 函式式介面 Consumer & Supplier 以及 JAVA新紀元 λ表示式的到來

lvgo發表於2018-08-24

JDK1.8 函式式介面 Consumer & Supplier 以及 JAVA新紀元 λ表示式的到來

背景什麼的被吞了,直接進入主題


函式式介面(定義自己百度,一大堆)

因為看了一些關於JDK1.8函式式介面的文章,發現基本上都是糊里糊塗一筆帶過.所以就抽空趕緊整理了一下.

還是附上幾個學習瞭解的傳送門 :


Consumer 函式式介面

JDK 原始碼

/**
 * 接受單個輸入引數並且不返回結果的操作。
 * 與大多數其他功能介面不同, Consumer預期通過副作用進行操作。
 *
 * @since 1.8
 */
@FunctionalInterface
public interface Consumer<T> {

    /**
     * 對給定的引數執行此操作。
     *
     * @param t the input argument
     */
    void accept(T t);

    /**
     * 返回一個組合的Consumer ,依次執行此操作,然後執行after操作。 
     * 如果執行任一操作會丟擲異常,它將被轉發到組合操作的呼叫者。 
     * 如果執行此操作會引發異常,則不會執行after操作。
     *
     * @param 此操作後執行的操作
     * @return 一個組成的 Consumer ,依次執行 after操作
     * @throws NullPointerException - if after is null
     */
    default Consumer<T> andThen(Consumer<? super T> after) {
        Objects.requireNonNull(after);
        return (T t) -> { accept(t); after.accept(t); };
    }

複製程式碼

剛拿過來看的時候可能會有一些繞,但是我們換個角度來看一下.

Consumer 直譯過來就是消費者的意思,那我們是不是可以理解成消費程式碼.既然他要消費,那我們就要給他提供程式碼.

來看一個簡單的demo

public void testConsumer1() {
        Consumer<String> consumer = new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s + "?");
            }
        };
        consumer.accept("李磊");
    }
複製程式碼

輸出結果

李磊?
複製程式碼

簡單解釋一下

Consumer是一個介面,所以當我們直接使用的話,要實現其 accept()方法,而這個方法的引數,就是我們定義介面時候給到的泛型,這裡給的是一個String型別,方法當中的內容,就是我們所謂的消費程式碼,當呼叫accept()方法時執行.

注意 : 也就是上面提到的通過副作用處理,我不清楚這個單詞翻譯的是否準確,看了很多博主和一些機器翻譯都是這個意思,但我個人的理解意思,更趨近於說是通過側面來解決問題.

再看一下 consumer.accept("李磊")這一句,這裡便是真正的執行的地方,也就是呼叫的我們剛剛自行實現的accept()方法.

讓我們繼續剛剛的demo往下看

這種寫法和上面在JDK1.8環境中是等價的. 主要就是利用到了1.8中的 λ 表示式.

    public void testConsumer1() {
        Consumer<String> consumer = s -> System.out.println(s + "?");
        consumer.accept("李磊");
    }

複製程式碼

下面的例子均使用λ表示式完成

泛型為自定義物件時

public void testConsumerToSupplier() {
        Consumer<Person> consumer = person -> {
            person.setName("張穎");
            person.setSize(34);
        };
        Person person = new Person();
        consumer.accept(person);
        System.out.println("person = " + person);
    }

複製程式碼

輸入結果:

person = Person{name='張穎', size=34}
複製程式碼

泛型為自定義介面時

public interface People {
    void come(Person person);
}
複製程式碼
public void testConsumerAndInterfaceFunction() {
        Consumer<People> consumer = people -> {
            people.come(new Person("李四", 23));
            people.come(new Person("找錢", 34));
            people.come(new Person("孫儷", 45));
        };

        consumer.accept(this::print);
    }

    public void print(Person person) {
        System.out.println("person = " + person);
    }
複製程式碼

輸出結果

person = Person{name='李四', size=23}
person = Person{name='找錢', size=34}
person = Person{name='孫儷', size=45}
複製程式碼

如果到了這裡還沒有明白怎麼回事,我建議你親自動手敲上那麼一遍.真的,如果還不懂來杭州,我當面給你講.


Supplier 函式式介面

還是一樣,先看一下JDK原始碼

/**
 * 獲得物件的一個函式式介面
 *
 * @since 1.8
 */
@FunctionalInterface
public interface Supplier<T> {

    /**
     * 得到一個物件
     *
     * @return 目標物件
     */
    T get();
}

複製程式碼

這個是不是看起來很容易理解了,Supplier的意思是供應商,那我們是不是可以把他理解成一個商場,然後你告訴他你想要的東西是什麼樣子的,它是不是就會給你了.

來看一下這個簡單的demo

void testSupplier1() {
        Supplier<String> supplier = () -> "這是你要的字串";
        String str = supplier.get();
        System.out.println("str = " + str);
    }
複製程式碼

執行結果:

str = 這是你要的字串
複製程式碼

繼續自定義物件

void testSupplier2() {
        Supplier<Person> supplier = () -> {
            Person person = new Person();
            person.setName("張三");
            person.setSize(32);
            return person;
        };

        Person person = supplier.get();
        System.out.println("person = " + person);
    }
複製程式碼

執行結果

person = Person{name='張三', size=32}
複製程式碼

再來刺激的自定義介面

    void testSupplier3() {
        Supplier<People> supplier = new Supplier<People>() {
            @Override
            public People get() {
                People people = new People() {
                    @Override
                    public void come(Person person) {
                        System.out.println("person = " + person)
                    }
                };
                return people;
            }
        };

        People people = supplier.get();
        people.come(new Person("李四", 24));
    }

複製程式碼

輸出結果

person = Person{name='李四', size=24}
複製程式碼

看好別眨眼,λ表示式的寫法 下面的一行和上面的一堆是等價的

void testSupplier4() {
    Supplier<People> supplier = () -> person -> System.out.println("person = " + person);
    People people = supplier.get();
    people.come(new Person("李四", 24));
}
複製程式碼

輸出結果

person = Person{name='李四', size=24}
複製程式碼

想必看到這你不光明白了 Supplier的用法,更清楚的λ表示式的用處了.


寫在最後,寫這篇文章的原因是因為在整理工廠模式的時候遇到的一些問題

工廠模式簡單的是不能再簡單了,但是隨著技術的發展,也出現了一些新穎的工廠方法.CTS便是其中之一.

至於Consumer&Supplier應用在工廠模式的程式碼如下,因為比較特殊,寫在了一起,想要親自體檢覆制貼上執行TTT類的main()方法即可

/**
 * @author lvgo
 * @version 1.0
 * @Description: CTS實現工廠模式
 * @date 18-8-24 下午3:57
 */
public interface CTS {

    static CTS getCts(Consumer<Peoples> consumer) {
        Map<String, Supplier<Persons>> map = new HashMap<>();
        consumer.accept(map::put);
        return person -> map.get(person).get();

    }

    Persons getPerson(String name);
}

interface Peoples {
    void come(String name, Supplier<Persons> personSupplier);
}

class TTT {
    public static void main(String[] args) {
        CTS cts = CTS.getCts(people -> {
            people.come("張三", () -> new Persons("張三"));
            people.come("李四", () -> new Persons("李四"));
            people.come("王五", () -> new Persons("王五"));
        });

        Persons person = cts.getPerson("王五");
        System.out.println("persons = " + person);
    }
}

class Persons {

    private String name;

    public Persons() {
    }

    public Persons(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + "'}'";
    }
}

複製程式碼

CTS工廠模式說明: Consumer To Supplier 自造詞,無處可尋,他處偶遇純屬抄襲;

通過Peoples介面的come()方法,可以動態在CTS工廠內新增person,然後使其具於生產該例項的能力.



參考文獻

相關文章