Java 8 預覽之Functional Interface

轉自:http://zyzhang.github.io/blog/2013/06/15/java8-preview-functional-interface/

在JDK的類庫中,有很多隻聲明瞭一個方法的接口,比如java.lang.Iterable<T>java.lang.Runnable。這些接口被稱爲單抽象方法接口(Single Abstract Method interfaces),它表達了一種邏輯上的單一功能約定。

Java 8爲這樣的接口引入了一個新概念——函數式接口(Functional Interface),同時引入註解@FunctionalInterface以幫助編譯器檢查函數式接口的合法性。

何爲函數式接口

JSR 335中這樣描述函數式接口:

A functional interface is an interface that has just one abstract method, and thus represents a single function contract. (In some cases, this “single” method may take the form of multiple abstract methods with override-equivalent signatures (8.4.2) inherited from superinterfaces; in this case, the inherited methods logically represent a single method.)

函數式接口和所謂的Single Abstract Method interfaces一樣,就是隻包含一個抽象方法的接口,表達的是邏輯上的單一功能,例如:

  • java.lang.Runnable就是一個函數式接口, 因爲它只有一個抽象方法:
public interface Runnable {
    public abstract void run();
}
  • java.lang.Iterable<T>雖然有兩個方法,但它仍然是函數式接口,因爲forEach方法是一個Default Method,它有其默認實現,且不強制要求實現該接口的類或繼承該接口的子接口重寫(Override)該方法,因此,在邏輯上,java.lang.Iterable<T>仍然是隻約定一個iterator方法的函數式接口。
public interface Iterable<T> {
    Iterator<T> iterator();
    default void forEach(Consumer<? super T> action) {
        // 省略實現代碼
    }
}

函數式接口與Lambda

函數式接口的一個非常重要的用途就是對Lambda提供支持,看下面的例子:

public class Book {
    public String name;
    public String author;
    public double price;
}

public class BookStore {
    private List<Book> books = new ArrayList<>();
}

現在我希望BookStore能夠篩選出BookStore中符合某種條件書籍,篩選條件可能多種多樣,比如,所有Martin Fowler的著作,或者價格大於某個金額的所有書籍,於是,我們新增了BookFilter接口,並且爲BookStore添加了list方法:

public interface BookFilter {
    boolean test(Book book);
}

public class BookStore {
    private List<Book> books = new ArrayList<>();

    public List<Book> list(BookFilter filter) {
        List<Book> result = new ArrayList<>();
        books.forEach(book -> {
            if (filter.test(book)) {
                result.add(book);
            }
        });
        return result;
    }
}

現在,我們就可以在調用list方法時使用Lambda表達式了:

// 篩選出所有價格大於15.0的書籍
bookStore.list(book -> book.price > 15.0)

因爲BookFilter是一個函數式接口,只具有一個抽象方法,所以在編譯期可以很容易推斷Lambda表達式和BookFilter是否匹配,於是Lambda表達式的實現就簡單了。

JDK提供的通用函數式接口

上面代碼中的BookFilter實際上只是一個斷言:如果Book符合某種條件則返回true,否則返回false。我們完全可以將這個概念抽象成Predicate供所有人使用,這樣項目中就不會充斥過量的僅爲Lambda服務的函數式接口了。Java 8的設計者同樣考慮到了這個問題,於是新增了java.util.function包,提供通用的函數式接口。Predicate<T>就是其中之一。

於是,上面的list方法使用Predicate就足夠了,我們可以痛快的把BookFilter扔進回收站了。

public List<Book> list(Predicate<Book> predicate) {
    List<Book> result = new ArrayList<>();
    books.forEach(book -> {
        if (predicate.test(book)) {
            result.add(book);
        }
    });
    return result;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章