上一篇博客Java8函數(shù)式編程之二 : Lambda表達式 - 簡書?介紹了Lambda表達式喝峦,最后也留下了一個問題互躬,就是Lambda到底用在什么地方,以及什么是函數(shù)式接口庐氮?
還記得我們在第一篇博客中定義的這個接口嗎?
public interfaceTradePredicate {
booleantest(Trade trade);
}
這就是一個函數(shù)式接口漆弄。那么怎樣去鑒別一個接口是否是函數(shù)式接口呢饱搏?
簡單的說:函數(shù)式接口就是只定義了一個抽象方法的接口。比如JavaAPI中的Comparator 和Runnable置逻。
public interface Comparator{
int compare(T o1, T o2);
}
public interface Runnable{
void run();
}
————————
注意:函數(shù)式接口是只定義“一個抽象方法”的接口推沸,只定義一個抽象方法并代表沒有其他方法,后面我們知道券坞,接口里還可以有默認方法鬓催。
————
我們也可以說,加上注解@FunctionalInterface的接口(只有一個抽象方法的接口)恨锚,就是一個函數(shù)式接口宇驾。
——————
關(guān)于函數(shù)式接口,注意以下幾點:
1.如果一個接口只有一個抽象方法猴伶,那么該接口就是函數(shù)式接口课舍。
2.如果我們在某個接口上聲明了@FunctionalInterface注解,那么編譯器就會按照函數(shù)式接口的定義來要求該接口他挎。
3.如果某個接口只有一個抽象方法筝尾,但我們并沒有給該接口聲明@FunctionalInterface注解,那么編譯器依舊會將其看作是函數(shù)式接口办桨。
————————————
@FunctionalInterface
public interfaceMyInterface {
public voidtest();
publicString myString();
}
這樣會報錯筹淫;
Invalid'@FunctionalInterface'annotation; MyInterface is not a functional interface
——————————
但是!
@FunctionalInterface
public interfaceMyInterface {
public voidtest();
publicString toString();
}
如果是這樣呢撞,就不會報錯损姜,為什么呢?
————————
我們看看Java Document文檔是怎么說的:
Ifan interface declares an abstract method overriding one of the
public methods of {@codejava.lang.Object}, that also does
notcount toward the interface's abstract method count
since any implementation of the interface will have an
implementation from {@codejava.lang.Object} or elsewhere.
簡單的解釋就是:當你重寫的方法是Object類的方法時殊霞,并不會算在“抽象方法”內(nèi)摧阅。
————————————
函數(shù)式接口的實例可以通過Lambda表達式,方法引用或者構(gòu)造方法引用來創(chuàng)建绷蹲。
————————————
我們來看看使用各種方式來遍歷集合棒卷,對比其特點:
public classTest {
public static voidmain(String[] args) {
List list = Arrays.asList(1,2,3,4,5,6,7,8,9);
//使用for循環(huán)
for(inti =0; i < list.size(); ++i) {
System.out.print(list.get(i));
}
//增強的for循環(huán)
for(Integer i : list) {
System.out.print(i);
}
//匿名內(nèi)部類
list.forEach(newConsumer() {
@Override
public voidaccept(Integer integer) {
System.out.print(integer);
}
});
//Lambda表達式
list.forEach(i -> {
System.out.print(i);
});
}
}
————————————————————
你可能對forEach()這個方法并不熟悉,我們可以看看它的Javadoc說明瘸右。
/**
* Performs the given action for each element of the {@codeIterable}
* until all elements have been processed or the action throws an
* exception.? Unless otherwise specified by the implementing class,
* actions are performed in the order of iteration (if an iteration order
* is specified).? Exceptions thrown by the action are relayed to the
* caller.
通過對forEach()方法注釋的理解娇跟,我們發(fā)現(xiàn)其執(zhí)行的的是一種給定的動作岩齿。
————————
那為何不繼續(xù)看看forEach()方法的實現(xiàn)呢太颤?
default voidforEach(Consumer action) {
Objects.requireNonNull(action);
for(Tt :this) {
action.accept(t);
}
}
————————
問題1:
你可能會疑惑,default是什么呢盹沈?好像以前沒有這個關(guān)鍵字龄章,并且這個方法是有實現(xiàn)的吃谣。這就是我們先前說的默認方法,Java8中做裙,接口里是可以有方法實現(xiàn)的岗憋,這種方法就是默認方法。這是個很好的設計锚贱,即有利于Java8的新的特性的加入仔戈,又很好的兼容了以前的Java版本。
——————————
問題2:forEach()里接收的參數(shù)類型是Consumer, 這個又是什么呢拧廊,有什么用呢监徘?
這個當然是函數(shù)式接口,不夠是Java8為我們提供的吧碾,還有類似的接口如Predicate,Function等等凰盔。在下一篇博客中將詳細介紹它們。