轉自: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;
}