城市就是森林,每一個男人都是獵手,每一個女人都是陷阱。——《三體》
在哪使用Lambda表達式?
在上一篇文章(傳送門)中介紹了Lambda表達式的基本語法,其中的舉了一個Lambda表達式的例子,就是按照品牌給口罩列表進行排序:
maskList.sort((Mask o1, Mask o2) -> o1.getBrand().compareTo(o2.getBrand()));
這里使用的sort
方法的參數類型是Comparator<T>
,我們就是把Lambda表達式作為Comparator<T>
傳入sort
方法中的。Comparator<T>
就是一個函數式接口,那么什么是函數式接口?
歡迎關注微信公眾號:萬貓學社,每周一分享Java技術干貨。
函數式接口
函數式接口就是有且僅有一個抽象方法的接口。上面提到的Comparator<T>
接口,雖然有很多默認方法,但有且僅有一個抽象方法compare
,所以它仍然是一個函數式接口。再舉個例子:
package java.util.concurrent;
@FunctionalInterface
public interface Callable<V> {
V call() throws Exception;
}
Callable
接口只有一個call
抽象方法,所以它也是函數式接口。
你可以已經發現了,Callable
接口上有一個注解@FunctionalInterface
,該注解用於標志該接口是一個函數式接口。如果你編寫了一個不是函數式接口的接口,並且加了@FunctionalInterface
注解,編譯就會報錯,需要注意一下。
看了以上的例子,是不是擼胳膊挽袖子准備大干一場?別急,檢驗出真知,我們先簡單測試一下。以下三個接口,哪些是函數式接口,哪些不是函數式接口?
- Runnable
package java.lang;
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
- Task
package com.sun.jmx.snmp.tasks;
public interface Task extends Runnable {
public void cancel();
}
- Serializable
package java.io;
public interface Serializable {
}
請思考片刻…
.
.
.
.
.
.
宣布答案:
Runnable
只有一個抽象方法run
,所以是函數式接口Task
有兩個抽象方法,分別是自己的cancel
方法和從Runnable
繼承而來的run
方法,所以不是函數式接口。Serializable
沒有任何一個方法,所以不是函數式接口。
怎么樣?都答對了嘛?
歡迎關注微信公眾號:萬貓學社,每周一分享Java技術干貨。
實現函數式接口
了解了什么是函數式接口以后,我們就可以直接使用Lambda表達式為函數式接口提供實現了,並且還可以把整個Lambda表達式作為函數式接口的實例。比如上面提到的Runnable
接口,我們就是這樣直接賦值:
Runnable runnable = () -> {
System.out.println("萬貓學社");
};
到目前為止,我們已經知道在哪使用Lambda表達式,那么該如何正確的使用Lambda表達式呢?
歡迎關注微信公眾號:萬貓學社,每周一分享Java技術干貨。
怎么使用Lambda表達式?
從上面Runnable
接口實例的例子中,可以看出:Runnable
接口的run
方法沒有入參沒有返回,該方法的簽名是() -> void
;Lambda表達式同樣的也沒有入參沒有返回,該表達式的簽名是() -> void
。
也就是說:函數式接口的抽象方法的簽名和Lambda表達式的簽名必須一致。
再比如,按照品牌給口罩列表進行排序的例子,Comparator<T>
接口的compare
方法的簽名是(T ,T) -> int
,Lambda表達式的簽名同樣也是(T ,T) -> int
。
為了加深理解,我們再來做個小測試,看看哪些代碼正確使用了Lambda表達式?
Callable
Callable<String> callable = () -> {
return "萬貓學社";
};
Runnable
Runnable runnable = () -> {
return "萬貓學社";
};
Comparator<Mask>
maskList.sort((Mask o1, Mask o2) -> {
if (o1.getBrand().equals(o2.getBrand())) {
return o1.getType().compareTo(o2.getType());
} else {
return o1.getBrand().compareTo(o2.getBrand());
}
});
請思考片刻…
.
.
.
.
.
.
宣布答案:
Callable
:正確,Lambda表達式的簽名是() -> String
,與Callable<String>
接口的唯一抽象方法call
的簽名匹配,所以是正確的。Runnable
:錯誤,Lambda表達式的簽名是() -> String
,但是Runnable
接口的唯一抽象方法run
的簽名是() -> void
,兩者不匹配,所以是錯誤的。Comparator<Mask>
:正確,Lambda表達式的簽名是(Mask, Mask) -> int
,與Comparator<Mask>
接口的唯一抽象方法compare
的簽名匹配,所以是正確的。
怎么樣?都答對了嘛?
歡迎關注微信公眾號:萬貓學社,每周一分享Java技術干貨。
總結
有且僅有一個抽象方法的接口叫做函數式接口,Lambda表達式可以直接作為函數式接口的實例,函數式接口的抽象方法的簽名和Lambda表達式的簽名必須一致。
歡迎關注微信公眾號:萬貓學社,每周一分享Java技術干貨。
《死磕Lambda表達式》系列
- 死磕Lambda表達式(一):初識Lambda
- 死磕Lambda表達式(二):Lambda的使用
- 死磕Lambda表達式(三):更簡潔的Lambda
- 死磕Lambda表達式(四):常用的函數式接口
- 死磕Lambda表達式(五):Comparator復合
- 死磕Lambda表達式(六):Consumer、Predicate、Function復合
歡迎關注微信公眾號:萬貓學社,每周一分享Java技術干貨。