【Java8新特性】04 詳解Lambda表達式中Predicate Function Consumer Supplier函數式接口

Java8 由Oracle在2014年發佈,是繼Java5之後最具革命性的版本。

Java8吸收其他語言的精髓帶來了函數式編程,lambda表達式,Stream流等一系列新特性,學會了這些新特性,可以讓你實現高效編碼優雅編碼。

熱門精選文章,更多技術乾貨,微信搜索訂閱號【碼者圈】
【Java8新特性】04 詳解Lambda表達式中Predicate Function Consumer Supplier函數式接口
【Java8新特性】03 Stream流式數據處理
【Java8新特性】02 函數式接口和Lambda表達式實戰練習:環繞執行模式使行爲參數化
【Java8新特性】01 函數式接口和Lambda表達式你真的會了嗎

函數式接口

函數式接口是指只定義了一個抽象方法的接口,不包括default默認方法。

函數式接口的抽象方法的簽名稱爲函數描述符,通過函數描述符可以很好得到Lambda表達式的簽名。

常見的函數式接口有:Runnable, Callable, Comparator等。除此之外,Java8設計者還新增了一些比較抽象的函數式接口,比如:Predicate, Consumer, Supplier, Function, UnaryOperator, BinaryOperator等, 這些函數式接口定義在java.util.function包中。

接下來詳細介紹function包中定義的抽象接口:

1. Predicate

(1)定義

Predicate是謂詞的意思,用來判斷泛型T對象是否符合條件,如果符合返回true,否則返回false。

查看jdk源碼,定義了一個抽象方法test:

@FunctionalInterface
public interface Predicate<T> {

    /**
     * Evaluates this predicate on the given argument.
     *
     * @param t the input argument
     * @return {@code true} if the input argument matches the predicate,
     * otherwise {@code false}
     */
    boolean test(T t);
}

(2)使用方法

Predicate是一個接口所以不能直接實例化,可以使用匿名類或者Lambda表達式實例化。以Lambda爲例:

// 接收string對象,判斷是否爲空,返回boolean
Predicate predicate = (String str) -> str.isEmpty();

下面以一個校驗參數的實例說明:

@Test
public void testPredicate() {
    String input = "hello java8";
    if (validate(input, (str) -> !str.isEmpty() && str.length() > 5)) {
        // 校驗輸入
        System.out.println("valid input");
    }
}

// 第二個參數接收一個Predicate實例
private <T> boolean validate(T input, Predicate<T> predicate) {
    return predicate.test(input);
}

(3)函數描述符

Predicate: T -> boolean

接受泛型T對象返回boolean。

注意:java.util.function包中還針對基本類型封裝了類似IntPredicate, LongPredicate等接口,這無非是表明只接受Int或Long類型的輸入,後面Consumer等函數式接口與這個類似,本文不再贅述。

2. Consumer

(1)定義

Consumer是消費者的意思,用來接收一個泛型T對象,執行相關操作,最後返回void。

查看jdk源碼,定義了一個抽象方法accept:

@FunctionalInterface
public interface Consumer<T> {

    /**
     * Performs this operation on the given argument.
     *
     * @param t the input argument
     */
    void accept(T t);
}

(2)使用方法

使用Lambda表達式實例化Consumer接口:

Consumer<String> consumer = (str) -> System.out.println(str);

下面以打印字符串的實例講解Consumer的用法:

@Test
public void testConsumer() {
    String input = "hello java8";
    // 打印輸入
    consume(input, (str) -> System.out.println(str));
}

private <T> void consume(T input, Consumer<T> consumer) {
    consumer.accept(input);
}

(3)函數描述符

Consumer: T -> void

接受泛型T對象返回void。

3. Supplier

(1)定義

Supplier是提供者的意思,用來生成泛型T對象。

查看jdk源碼,定義了一個抽象方法get:

@FunctionalInterface
public interface Supplier<T> {

    /**
     * Gets a result.
     *
     * @return a result
     */
    T get();
}

(2)使用方法

使用Lambda表達式實例化Supplier接口:

Supplier supplier = () -> "Hello Java8 supplier";

下面以獲取當前時間的實例講解Supplier的用法:

@Test
public void testSupplier() {
    // 獲取當前時間
    Long currentTime = supply(() -> System.currentTimeMillis());
}

private <T> T supply(Supplier<T> supplier) {
    return supplier.get();
}

(3)函數描述符

Supplier: void -> T

接受void返回泛型T對象。

4. Function

(1)定義

Function是函數的意思,用來定義一個抽象函數,接收泛型T對象,返回泛型R對象。

查看jdk源碼,定義了一個抽象方法apply:

@FunctionalInterface
public interface Function<T, R> {

    /**
     * Applies this function to the given argument.
     *
     * @param t the function argument
     * @return the function result
     */
    R apply(T t);
}

(2)使用方法

使用Lambda表達式實例化Function接口:

Function<String, Integer> function = (str) -> str.length();

下面以判斷輸入是否以指定字符串開頭的實例講解Function的用法:

@Test
public void testFunction() {
    String input = "hello java8";
    if(func(input, (String str) -> str.startsWith("hello"))) {
        System.out.println("start with hello");
    }

}

private <T, R> R func(T t, Function<T, R> function) {
    return function.apply(t);
}

(3)函數描述符

Function: T -> R

接受泛型T對象,返回泛型R對象。

5. UnaryOperator

(1)定義

UnaryOperator是一元操作符的意思,接收一個泛型T對象參數,返回相同T類型對象。

查看jdk源碼,UnaryOperator繼承自Function接口,定義了一個identity方法:

@FunctionalInterface
public interface UnaryOperator<T> extends Function<T, T> {

    /**
     * Returns a unary operator that always returns its input argument.
     *
     * @param <T> the type of the input and output of the operator
     * @return a unary operator that always returns its input argument
     */
    static <T> UnaryOperator<T> identity() {
        return t -> t;
    }
}

(2)使用方法

使用Lambda表達式實例化UnaryOperator接口:

UnaryOperator<Integer> unaryOperator = (Integer i) -> i * i;

下面以整數遞增的實例講解UnaryOperator的用法:

@Test
public void testUnaryOperator() {
    UnaryOperator<Integer> unaryOperator = (Integer i) -> i * i;
    
    int input = 0;
    int result = unaryOperate(input, (Integer i) -> i + 1);
    // output: 1
    System.out.println(result);
}

private <T> T unaryOperate(T t, UnaryOperator<T> unaryOperator) {
    return unaryOperator.apply(t);
}

(3)函數描述符

UnaryOperator: T -> T

接受泛型T對象,返回泛型T對象。

6. BinaryOperator

(1)定義

BinaryOperator是二元操作符的意思,接收兩個相同泛型參數類型T,返回R類型對象。

查看jdk源碼,BinaryOperator繼承自BiFunction接口,繼承了BiFunction的apply方法:

@FunctionalInterface
public interface BinaryOperator<T> extends BiFunction<T,T,T> {
    /**
     * Applies this function to the given arguments.
     *
     * @param t the first function argument
     * @param u the second function argument
     * @return the function result
     */
    R apply(T t, U u);
}

(2)使用方法

使用Lambda表達式實例化BinaryOperator接口:

BinaryOperator<String> binaryOperator = (String str1, String str2) -> str1 + str2;

下面以整數求和實例講解BinaryOperator的用法:

@Test
public void testBinaryOperator() {
    int a1 = 10;
    int a2 = 20;
    
    int sum = binaryOperate(a1, a2, (Integer i1, Integer i2) -> i1 + i2);
    // output: 30
    System.out.println(sum);
}

private <T> T binaryOperate(T t1, T t2, BinaryOperator<T> binaryOperator) {
    return binaryOperator.apply(t1, t2);
}

(3)函數描述符

BinaryOperator: (T, T) -> T

接受兩個泛型T對象,返回一個泛型T對象。

7. 總結

java.util.function包中定義了很多函數式抽象接口,只要記住它們的函數描述符就可以很方便的知道他們的使用方法。

  • Predicate: T -> boolean
  • Consumer: T -> void
  • Supplier: void -> T
  • Function: T -> R
  • UnaryOperator: T -> T
  • BinaryOperator: (T, T) -> T

【碼者圈】屬於編碼者自己的圈子,微信掃描二維碼關注,第一時間獲取更多技術乾貨!
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章