死磕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表達式》系列

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM