死磕Lambda表示式(二):Lambda的使用
城市就是森林,每一個男人都是獵手,每一個女人都是陷阱。——《三體》
在哪使用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表示式(四):常用的函式式介面