首頁 > 軟體

Java Lambda表示式常用的函數式介面

2022-04-07 19:01:41

前言:

在Java8支援Lambda表示式以後,為了滿足Lambda表示式的一些典型使用場景,JDK為我們提供了大量常用的函數式介面。它們主要在 java.util.function 包中,下面簡單介紹幾個其中的介面及其使用範例。

Supplier介面

Supplier介面是物件範例的提供者,定義了一個名叫get的抽象方法,它沒有任何入參,並返回一個泛型T物件,具體原始碼如下:

package java.util.function;

@FunctionalInterface
public interface Supplier<T> {
    T get();
}

原始碼比較簡單,我們來個例子。這是之前提過的表示口罩的類:

package one.more.study;

/**
 * 口罩
 */
public class Mask {
    public Mask(String brand, String type) {
        this.brand = brand;
        this.type = type;
    }
    /**
     * 品牌
     */
    private String brand;
    /**
     * 型別
     */
    private String type;

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }
}

下面我們使用Lambda表示式宣告一個Supplier的範例:

Supplier<Mask> supplier = () -> new Mask("3M", "N95");

用它來建立品牌為3M、型別為N95的Mask範例:

Mask mask = supplier.get();
System.out.println("Brand: " + mask.getBrand() + ", Type: " + mask.getType());

執行結果如下:

Brand: 3M, Type: N95

特別需要注意的是,本例中每一次呼叫get方法都會建立新的物件。

Consumer介面

Consumer介面是一個類似消費者的介面,定義了一個名叫accept的抽象方法,它的入參是一個泛型T物件,沒有任何返回(void),主要原始碼如下:

package java.util.function;

@FunctionalInterface
public interface Consumer<T> {
    void accept(T t);
}

結合上面的Supplier介面,我們來個例子:

Supplier<Mask> supplier = () -> new Mask("3M", "N95");
Consumer<Mask> consumer = (Mask mask) -> {
    System.out.println("Brand: " + mask.getBrand() + ", Type: " + mask.getType());
};
consumer.accept(supplier.get());

首先使用Lambda表示式宣告一個Supplier的範例,它是用來建立品牌為3M、型別為N95的Mask範例;再使用Lambda表示式宣告一個Consumer的範例,它是用於列印出Mask範例的相關資訊;最後Consumer消費了Supplier生產的Mask

執行結果如下:

Brand: 3M, Type: N95

Predicate介面

Predicate介面是判斷是與否的介面,定義了一個名叫test的抽象方法,它的入參是一個泛型T物件,並返回一個boolean型別,主要原始碼如下:

package java.util.function;

@FunctionalInterface
public interface Predicate<T> {
    boolean test(T t);
}

結合上面的Supplier介面,我們來個例子:

Supplier<Mask> supplier = () -> new Mask("3M", "N95");
Predicate<Mask> n95 = (Mask mask) -> "N95".equals(mask.getType());
Predicate<Mask> kn95 = (Mask mask) -> "KN95".equals(mask.getType());
System.out.println("是否為N95口罩:" + n95.test(supplier.get()));
System.out.println("是否為KN95口罩:" + kn95.test(supplier.get()));

首先使用Lambda表示式宣告一個Supplier的範例,它是用來建立品牌為3M、型別為N95的Mask範例;再使用Lambda表示式宣告一個Predicate的範例n95,它是用於判斷是否為N95口罩;再使用Lambda表示式宣告一個Predicate的範例kn95,它是用於判斷是否為KN95口罩;最後分別用兩個Predicate判斷Supplier生產的Mask

執行結果如下:

是否為N95口罩:true
是否為KN95口罩:false

Function介面

Function介面是對範例進行處理轉換的介面,定義了一個名叫apply的抽象方法,它的入參是一個泛型T物件,並返回一個泛型R物件,主要原始碼如下:

package java.util.function;

@FunctionalInterface
public interface Function<T, R> {
    R apply(T t);
}

結合上面的Supplier介面,我們來個例子:

Supplier<Mask> supplier = () -> new Mask("3M", "N95");
Function<Mask, String> brand = (Mask mask) -> mask.getBrand();
Function<Mask, String> type = (Mask mask) -> mask.getType();
System.out.println("口罩品牌:" + brand.apply(supplier.get()));
System.out.println("口罩型別:" + type.apply(supplier.get()));

首先使用Lambda表示式宣告一個Supplier的範例,它是用來建立品牌為3M、型別為N95的Mask範例;再使用Lambda表示式宣告一個Function的範例brand,它是用於獲取口罩的品牌;再使用Lambda表示式宣告一個Function的範例type,它是用於獲取口罩的型別;最後分別用兩個Function分析Supplier生產的Mask

執行結果如下:

口罩品牌:3M
口罩型別:N95

BiFunction介面

Function介面的入參只有一個泛型物件,JDK還為我們提供了兩個泛型物件入參的介面:BiFunction介面,主要原始碼如下:

package java.util.function;

@FunctionalInterface
public interface BiFunction<T, U, R> {
    R apply(T t, U u);
}

我們可以用BiFunction介面傳入兩個String直接建立Mask範例:

BiFunction<String,String,Mask> biFunction = (String brand, String type) -> new Mask(brand, type);
Mask mask = biFunction.apply("3M", "N95");
System.out.println("Brand: " + mask.getBrand() + ", Type: " + mask.getType());

執行結果如下:

Brand: 3M, Type: N95

基本資料型別

以上介紹的幾個常用的函數式介面入參和返回,都是泛型物件的,也就是必須為參照型別。當我們傳入或獲取的是基本資料型別時,將會發生自動裝箱和自動拆箱,帶來不必要的效能損耗,比如:

Supplier&lt;Long&gt; supplier = () -&gt; System.currentTimeMillis();
long timeMillis = supplier.get();

在上面例子裡,發生了一次自動裝箱(long被裝箱為Long)和一次自動拆箱(Long被拆箱為long),如何避免這種不必要的效能損耗呢?JDK為我們提供相應的函數式介面,如LongSupplier介面,定義了一個名叫getAsLong的抽象方法,簽名是() -> long

上面的例子可以優化為:

LongSupplier supplier = () -&gt; System.currentTimeMillis();
long timeMillis = supplier.getAsLong();

類似這樣的介面還有很多,我為大家整理了一下:

Supplier相關的介面

介面名稱方法名稱方法簽名
Supplierget() -> T
BooleanSuppliergetAsBoolean() -> boolean
DoubleSuppliergetAsDouble() -> double
IntSuppliergetAsInt() -> int
LongSuppliergetAsLong() -> long

Consumer相關的介面

介面名稱方法名稱方法簽名
Consumeraccept(T) -> void
DoubleConsumeraccept(double) -> void
IntConsumeraccept(int) -> void
LongConsumeraccept(long) -> void
ObjDoubleConsumeraccept(T, double) -> void
ObjIntConsumeraccept(T, int) -> void
ObjLongConsumeraccept(T, long) -> void

Predicate相關的介面

介面名稱方法名稱方法簽名
Predicatetest(T) -> boolean
BiPredicatetest(T, U) -> boolean
DoublePredicatetest(double) -> boolean
IntPredicatetest(int) -> boolean
LongPredicatetest(long) -> boolean

Function相關的介面

介面名稱方法名稱方法簽名
Functionapply(T) -> R
BiFunctionapply(T, U) -> R
DoubleFunctionapply(double) -> R
DoubleToIntFunctionapplyAsInt(double) -> int
DoubleToLongFunctionapplyAsLong(double) -> long
IntFunctionapply(int) -> R
IntToDoubleFunctionapplyAsDouble(int) -> double
IntToLongFunctionapplyAsLong(int) -> long
LongFunctionapply(long) -> R
LongToDoubleFunctionapplyAsDouble(long) -> double
LongToIntFunctionapplyAsInt(long) -> int
ToDoubleFunctionapplyAsDouble(T) -> double
ToDoubleBiFunctionapplyAsDouble(T, U) -> double
ToIntFunctionapplyAsInt(T) -> int
ToIntBiFunctionapplyAsInt(T, U) -> int
ToLongFunctionapplyAsLong(T) -> long
ToLongBiFunctionapplyAsLong(T, U) -> long

到此這篇關於Java Lambda表示式常用的函數式介面的文章就介紹到這了,更多相關Lambda函數式介面內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com