1. 程式人生 > >死磕Lambda表示式(二):Lambda的使用

死磕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註解,編譯就會報錯,需要注意一下。

看了以上的例子,是不是擼胳膊挽袖子準備大幹一場?別急,檢驗出真知,我們先簡單測試一下。以下三個介面,哪些是函式式介面,哪些不是函式式介面?

  1. Runnable
package java.lang;

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}
  1. Task
package com.sun.jmx.snmp.tasks;

public interface Task extends Runnable {
    public void cancel();
}
  1. Serializable
package java.io;

public interface Serializable {
}

請思考片刻…
.
.
.

.
.
.
宣佈答案:

  1. Runnable只有一個抽象方法run,所以是函式式介面
  2. Task有兩個抽象方法,分別是自己的cancel方法和從Runnable繼承而來的run方法,所以不是函式式介面。
  3. 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表示式?

  1. Callable
Callable<String> callable = () -> {
    return "萬貓學社";
};
  1. Runnable
Runnable runnable = () -> {
    return "萬貓學社";
};
  1. 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());
    }
});

請思考片刻…
.
.
.

.
.
.
宣佈答案:

  1. Callable:正確,Lambda表示式的簽名是() -> String,與Callable<String>介面的唯一抽象方法call的簽名匹配,所以是正確的。
  2. Runnable:錯誤,Lambda表示式的簽名是() -> String,但是Runnable介面的唯一抽象方法run的簽名是() -> void,兩者不匹配,所以是錯誤的。
  3. Comparator<Mask>:正確,Lambda表示式的簽名是(Mask, Mask) -> int,與Comparator<Mask>介面的唯一抽象方法compare的簽名匹配,所以是正確的。

怎麼樣?都答對了嘛?

歡迎關注微信公眾號:萬貓學社,每週一分享Java技術乾貨。

總結

有且僅有一個抽象方法的介面叫做函式式介面,Lambda表示式可以直接作為函式式介面的例項,函式式介面的抽象方法的簽名和Lambda表示式的簽名必須一致。

歡迎關注微信公眾號:萬貓學社,每週一分享Java技術乾貨。

《死磕Lambda表示式》系列

  • 死磕Lambda表示式(一):初識Lambda
  • 死磕Lambda表示式(二):Lambda的使用
  • 死磕Lambda表示式(三):更簡潔的Lambda
  • 死磕Lambda表示式(四):常用的函式式介面