首頁技術(shù)文章正文

Java培訓(xùn):深入解讀函數(shù)式接口

更新時(shí)間:2022-08-10 來源:黑馬程序員 瀏覽量:

  函數(shù)式編程是一種編程規(guī)范或一種編程思想,簡單可以理解問將運(yùn)算或?qū)崿F(xiàn)過程看做是函數(shù)的計(jì)算。 Java8為了實(shí)現(xiàn)函數(shù)式編程,提出了3個(gè)重要的概念:Lambda表達(dá)式、方法引用、函數(shù)式接口?,F(xiàn)在很多公司都在使用lambda表達(dá)式進(jìn)行代碼編寫,甚至知名的Java的插件也都在Lambda,比如數(shù)據(jù)庫插件MybatisPlus。Lambda表達(dá)式的使用是需要函數(shù)式接口的支持,即lambda表達(dá)式的核心就是使用大量的函數(shù)式接口。本文帶領(lǐng)大家全面了解函數(shù)式接口的定義和使用。

  一、文章導(dǎo)讀

  函數(shù)式接口概述

  自定義函數(shù)式接口

  常用函數(shù)式接口

  函數(shù)式接口的練習(xí)

  二、函數(shù)式接口概述

       1.函數(shù)式接口定義

  如果接口里只有一個(gè)抽象方法,那么就是函數(shù)式接口,可以使用注解(@FunctionalInterface)檢測該接口是否是函數(shù)式接口,即只能有一個(gè)抽象方法。

  注意事項(xiàng)

  函數(shù)式接口里可以定義默認(rèn)方法:默認(rèn)方法有方法體,不是抽象方法,符合函數(shù)式接口的定義要求。

  函數(shù)式接口里可以定義靜態(tài)方法:靜態(tài)方法也不是抽象方法,是一個(gè)有具體方法實(shí)現(xiàn)的方法,同樣也符合函數(shù)式接口的定義的。

  函數(shù)式接口里可以定義Object里的public方法(改成抽象方法):雖然它們是抽象方法,卻不需要覆蓋重寫,因?yàn)樗薪涌诘膶?shí)現(xiàn)類都是Object類的子類,而在Object類中有這些方法的具體的實(shí)現(xiàn)。

  2.函數(shù)式接口格式

```java
修飾符 interface 接口名稱 {
    //抽象方法
    public abstract 返回值類型 方法名稱(可選參數(shù)信息);
    //默認(rèn)方法
    public default 返回值類型 方法名稱(可選參數(shù)信息) {
        //代碼...        
    }
    //靜態(tài)方法
    public static 返回值類型 方法名稱(可選參數(shù)信息) {
        //代碼...        
    }
    //Object類的public方法變成抽象方法
    public abstract boolean equals(Object obj);
    public abstract String toString();    
}
```

  三、自定義函數(shù)式接口

  1. 自定義函數(shù)式接口舉例

  由于接口當(dāng)中抽象方法的`public abstract`是可以省略的,所以定義一個(gè)函數(shù)式接口很簡單:

```java
@FunctionalInterface
public interface MyFunctionalInterface {
    //抽象方法
    public abstract void method();
    //Object類的public方法變成抽象方法
    public abstract boolean equals(Object obj);
    public abstract String toString();
    //默認(rèn)方法
    public default void show(String s) {
        //打印小寫
        System.out.println(s.toLowerCase());
    }
    //靜態(tài)方法
    public static void print(String s) {
        //打印大寫
        System.out.println(s.toUpperCase());
    }
}
```

  
       2.自定義函數(shù)式接口的應(yīng)用

  對于剛剛定義好的`MyFunctionalInterface`函數(shù)式接口,典型使用場景就是作為方法的參數(shù):

```java
public class Demo01FunctionalInterface {
    public static void main(String[] args) {
        // 調(diào)用使用函數(shù)式接口的方法
        show(()->{
            System.out.println("Lambda執(zhí)行了");
        });
    }
    //定義方法使用函數(shù)式接口作為參數(shù)
    public static void show(MyFunctionalInterface mfi) {
        //調(diào)用自己定義的函數(shù)式接口
        mfi.method();
        String s = mfi.toString();
        System.out.println(s);
        boolean result = mfi.equals(mfi);
        System.out.println(result);
        mfi.show("world");
        MyFunctionalInterface.print("function");
    }
}
```

  
       3.運(yùn)行結(jié)果:

```
Lambda執(zhí)行了
Demo01FunctionalInterface$$Lambda$1/1078694789@3d075dc0
true
world
FUNCTION
```

  
       四、常用函數(shù)式接口

  前面我們自己定義了一個(gè)函數(shù)式接口,對于一些常用的函數(shù)式接口,每次自己定義非常麻煩。JDK提供了大量常用的函數(shù)式接口以豐富Lambda的典型使用場景,它們主要在`java.util.function`包中被提供。這樣的接口有很多,下面是最簡單的幾個(gè)接口及使用示例。

  1. Supplier接口

  
`java.util.function.Supplier`接口,它意味著"供給" , 對應(yīng)的Lambda表達(dá)式需要“**對外提供**”一個(gè)符合泛型類型的對象數(shù)據(jù)。

  
     1.1.抽象方法 : get

  Supplier`接口中包含一個(gè)抽象方法` T get(): 用來獲取一個(gè)泛型參數(shù)指定類型的對象數(shù)據(jù)。

```java

public class Demo02Supplier {
    public static void main(String[] args) {
        int num = getNum(() -> {
            return new Random().nextInt();
        });
        System.out.println(num);
    }
    public static int getNum(Supplier<Integer> supplier) {
        int num = supplier.get();
        return num;
    }
}
```

  
      1.2.求集合元素最大值
 

  使用`Supplier`接口作為方法參數(shù)類型,通過Lambda表達(dá)式求出List集合(存儲(chǔ)int數(shù)據(jù))中的最大值。提示:接口的泛型請使用`java.lang.Integer`類。

  代碼示例:

```java
public class Demo03Supplier {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        Collections.addAll(list,10,8,20,3,5);
        printMax(()->{
            return Collections.max(list);
        });
    }

    private static void printMax(Supplier<Integer> supplier) {
        int max = supplier.get();
        System.out.println(max);
    }
}
```

  
       2. Consumer接口

  `java.util.function.Consumer`接口則正好相反,它不是生產(chǎn)一個(gè)數(shù)據(jù),而是**消費(fèi)**一個(gè)數(shù)據(jù),其數(shù)據(jù)類型由泛型參數(shù)決定。

  2.1.抽象方法:accept

  `Consumer`接口中包含抽象方法`void accept(T t)`: 消費(fèi)一個(gè)指定泛型的數(shù)據(jù)。

  代碼示例:

```java
import java.util.function.Consumer;
//接收一個(gè)輸入?yún)?shù)x,把x的值擴(kuò)大2倍后,再+3做輸出
//類似于數(shù)學(xué)中的函數(shù): f(x) = 2*x + 3
public class Demo04Consumer {
    public static void main(String[] args) {
        int x = 3;
        consumeIntNum(x,(Integer num)->{
            System.out.println(2*num+3);
        });

    }
    /*
        定義方法,使用函數(shù)式接口Consumer作為方法參數(shù)
    */
    private static void consumeIntNum(int num,Consumer<Integer> function ) {
        function.accept(num);
    }
}
```

#### 2.2.默認(rèn)方法:andThen

如果一個(gè)方法的參數(shù)和返回值全都是`Consumer`類型,那么就可以實(shí)現(xiàn)效果:消費(fèi)一個(gè)數(shù)據(jù)的時(shí)候,首先做一個(gè)操作,然后再做一個(gè)操作,實(shí)現(xiàn)組合。而這個(gè)方法就是`Consumer`接口中的default方法`andThen`。下面是JDK的源代碼:

```java
default Consumer<T> andThen(Consumer<? super T> after) {
    Objects.requireNonNull(after);
    return (T t) -> { accept(t); after.accept(t); };
}
```

  
       2.2.默認(rèn)方法:andThen

  如果一個(gè)方法的參數(shù)和返回值全都是`Consumer`類型,那么就可以實(shí)現(xiàn)效果:消費(fèi)一個(gè)數(shù)據(jù)的時(shí)候,首先做一個(gè)操作,然后再做一個(gè)操作,實(shí)現(xiàn)組合。而這個(gè)方法就是`Consumer`接口中的default方法`andThen`。下面是JDK的源代碼:

```java
default Consumer<T> andThen(Consumer<? super T> after) {
    Objects.requireNonNull(after);
    return (T t) -> { accept(t); after.accept(t); };
}
```

  
       > 備注:`java.util.Objects`的`requireNonNull`靜態(tài)方法將會(huì)在參數(shù)為null時(shí)主動(dòng)拋出`NullPointerException`異常。這省去了重復(fù)編寫if語句和拋出空指針異常的麻煩。

  > `andThen`是默認(rèn)方法,由Consumer的對象調(diào)用,而且參數(shù)和返回值都是Consumer對象

  要想實(shí)現(xiàn)組合,需要兩個(gè)或多個(gè)Lambda表達(dá)式即可,而`andThen`的語義正是“一步接一步”操作。例如兩個(gè)步驟組合的情況:

  代碼示例:

```java
//接收一個(gè)字符串,先按照大寫打印,再按照小寫打印
/*
    toUpperCase(): 把字符串變成大寫
    toLowerCase(): 把字符串變成小寫
 */
public class Demo05Consumer {
    public static void main(String[] args) {
        String s = "Hello";
        //lambda標(biāo)準(zhǔn)格式
        fun(s, (String str) -> {
            System.out.println(s.toUpperCase());
        }, (String str) -> {
            System.out.println(s.toLowerCase());
        });
    }

    /*
        定義方法,參數(shù)是Consumer接口
        因?yàn)橐M(fèi)兩次,所以需要兩個(gè)Consumer接口作為參數(shù)
     */
    public static void fun(String s, Consumer<String> con1, Consumer<String> con2) {
        //先消費(fèi)一次
        con1.accept(s);
        //再消費(fèi)一次
        con2.accept(s);
    }
}
```

  運(yùn)行結(jié)果將會(huì)首先打印完全大寫的HELLO,然后打印完全小寫的hello。但是我們卻沒有使用andThen方法,其實(shí)我上面的寫法,就是andThen底層的代碼實(shí)現(xiàn)。

  為了方便大家理解,下面我們使用andThen方法進(jìn)行演示。

```java
public class Demo06Consumer {
    public static void main(String[] args) {
        String s = "HelloWorld";
        //2.lambda標(biāo)準(zhǔn)格式
        fun(s, (String str) -> {
            System.out.println(s.toUpperCase());
        }, (String str) -> {
            System.out.println(s.toLowerCase());
        });
    }

    /*
        定義方法,參數(shù)是Consumer接口
        因?yàn)橐M(fèi)兩次,所以需要兩個(gè)Consumer接口作為參數(shù)
     */
    public static void fun(String s, Consumer<String> con1, Consumer<String> con2) {

        con1.andThen(con2).accept(s);

    }
}
```

  運(yùn)行結(jié)果將會(huì)首先打印完全大寫的HELLO,然后打印完全小寫的hello。

  andThen原理分析圖解:

  

1660112398210_1.jpg

  ```txt

  注意:

  1.con1調(diào)用andThen方法,傳遞參數(shù)con2,所以anThen方法內(nèi)部的this就是con1,after就是con2

  2.andThen方法內(nèi)部調(diào)用accept方法,前面隱藏了一個(gè)this,this代表調(diào)用andThen方法的對象,就是con1

  3.andThen方法內(nèi)部的t是誰?就是最后調(diào)用方法accept傳遞的s

  this.accept(t) <==> con1.accept(s) ①

  4.con1調(diào)用andThen方法時(shí)傳遞的參數(shù)是con2,所以andThen方法內(nèi)部的after就是con2

  after.accept(t) <==> con2.accept(s) ②

  5.通過分析,我們發(fā)現(xiàn)①和②中的內(nèi)容,就是之前不用andThen方法,自己進(jìn)行調(diào)用的過程

  6.以上分析,仍然是按照面向?qū)ο笾蟹椒ㄕ{(diào)用的思路展開的,但實(shí)質(zhì)上,我們要注意,Consumer接口中的andThen方法,返回的是一個(gè)Consumer,里面采用的是lambda表達(dá)式,其實(shí)是在做函數(shù)模型的拼接,把兩個(gè)函數(shù)模型con1和con2拼接出一個(gè)新的模型,返回新的模型。所以con1.andThen(con2)是把con1和con2拼接成一個(gè)新的Consumer,返回的是lambda表達(dá)式的形式

  最后調(diào)用accept(s)方法時(shí),其實(shí)執(zhí)行的是lambda表達(dá)式{}中的代碼
、、、

  3. Function接口

  `java.util.function.Function`接口用來根據(jù)一個(gè)類型的數(shù)據(jù)得到另一個(gè)類型的數(shù)據(jù),前者稱為前置條件,后者稱為后置條件。有進(jìn)有出,所以稱為“函數(shù)Function”。

  3.1.抽象方法:apply

  `Function`接口中最主要的抽象方法為:`R apply(T t)`,根據(jù)類型T的參數(shù)獲取類型R的結(jié)果。

  代碼示例:

  將`String`類型轉(zhuǎn)換為`Integer`類型。

```java
/*
    java.util.function.Function<T,R>: 轉(zhuǎn)換型接口
        泛型T: 轉(zhuǎn)換前的類型
        泛型R: 轉(zhuǎn)換后的類型

        抽象方法:
            R apply(T t): 根據(jù)類型T的參數(shù)獲取類型R的結(jié)果 把參數(shù)t轉(zhuǎn)換成R類型的結(jié)果

        "123" --> 123

        需求:
            給你一個(gè)String類型的數(shù)字,給我轉(zhuǎn)換成int數(shù)字
            分析:
                用Function接口
                    T: 轉(zhuǎn)換前的類型, String
                    R: 轉(zhuǎn)換后的類型, Integer
 */
public class Demo07Function {
    public static void main(String[] args) {
        String s = "123";
        //lambda標(biāo)準(zhǔn)格式
        fun(s,(String str)->{return Integer.parseInt(str);});
    }
    /*
        定義方法,使用Function接口作為參數(shù)
     */
    public static void fun(String s,Function<String,Integer> function) {
        Integer num = function.apply(s);
        System.out.println(num);
    }
}
```

  3.2.默認(rèn)方法:andThen

  `Function`接口中有一個(gè)默認(rèn)的`andThen`方法,用來進(jìn)行組合操作。JDK源代碼如:

```java
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
    Objects.requireNonNull(after);
    return (T t) -> after.apply(apply(t));
}
```

  該方法同樣用于“先做什么,再做什么”的場景,和`Consumer`中的`andThen`差不多:

  代碼示例:

  將String的數(shù)字,轉(zhuǎn)成int數(shù)字,再把int數(shù)字?jǐn)U大10倍

```java
/*
    java.util.function.Function<T,R>: 轉(zhuǎn)換型接口
        泛型T: 轉(zhuǎn)換前的類型
        泛型R: 轉(zhuǎn)換后的類型

        默認(rèn)方法:
            default <V> Function<T, V> andThen(Function<R, V> after):
                先轉(zhuǎn)換一次,再轉(zhuǎn)換一次,一個(gè)挨著一個(gè)

        "123" --> 123 --> 1230 (擴(kuò)大了10倍)

        需求:
            給你一個(gè)String類型的數(shù)字,
                給我轉(zhuǎn)先換成int數(shù)字
                再給我把int數(shù)字?jǐn)U大10倍
            分析:
                用2個(gè)Function接口
                    第一個(gè)Function接口
                        T: 轉(zhuǎn)換前的類型, String
                        R: 轉(zhuǎn)換后的類型, Integer
                    第二個(gè)Function接口:
                        T: 轉(zhuǎn)換前的類型, Integer
                        R: 轉(zhuǎn)換后的類型, Integer
 */
public class Demo08Function {
    public static void main(String[] args) {
        String s = "123";
        //lambda標(biāo)準(zhǔn)格式
        fun(s,(String str)->{
            return Integer.parseInt(str);
        },(Integer num) -> {
            return num*10;
        });        
    }
    /*
        定義一個(gè)方法,有兩個(gè)Function接口作為參數(shù)
     */
    public static void fun(String s,Function<String,Integer> fun1,Function<Integer,Integer> fun2) {
        //1.先轉(zhuǎn)換一次
        Integer num1 = fun1.apply(s);
        //2.再轉(zhuǎn)換一次
        Integer num2 = fun2.apply(num1);
        System.out.println(num2);        
    }
}
```

  第一個(gè)操作是將字符串解析成為int數(shù)字,第二個(gè)操作是乘以10。兩個(gè)操作通過`andThen`按照前后順序組合到了一起。運(yùn)行結(jié)果將會(huì)打印1230。但是我們卻沒有使用andThen方法,其實(shí)我上面的寫法,就是andThen底層的代碼實(shí)現(xiàn)。

  > 請注意,F(xiàn)unction的前置條件泛型和后置條件泛型可以相同。

  為了方便大家理解,下面我們使用andThen方法進(jìn)行演示

  ```

public class Demo09Function {
    public static void main(String[] args) {
        String s = "123";
        //lambda標(biāo)準(zhǔn)格式
        fun(s,(String str)->{
            return Integer.parseInt(str);
        },(Integer num) -> {
            return num*10;
        });
       
    }
    /*
        定義一個(gè)方法,有兩個(gè)Function接口作為參數(shù)
     */
    public static void fun(String s,Function<String,Integer> fun1,Function<Integer,Integer> fun2) {
       Integer num3 = fun1.andThen(fun2).apply(s);
        System.out.println(num3);
    }
}
```

  運(yùn)行結(jié)果仍然是1230。

  andThen原理分析圖解:

  

1660113116767_2.jpg

  ```txt

  注意:

  1.fun1調(diào)用andThen方法傳遞參數(shù)fun2,所以andThen方法內(nèi)部的this就是fun1,after就是fun2

  2.andThen方法內(nèi)部直接調(diào)用apply方法,前面隱藏了一個(gè)this,this代表調(diào)用andThen方法的對象,就是fun1

  3.andThen方法內(nèi)部的t是誰?就是最后調(diào)用方法apply傳遞的s

  this.apply(t) <==> Integer num1 = fun1.apply(s) ①

  4.fun1調(diào)用andThen方法時(shí)傳遞的參數(shù)是fun2,所以andThen方法內(nèi)部的after就是fun2

  after.apply(this.apply(t)) <==> Integer num2 = fun2.apply(num1) ②

  5.通過分析,我們發(fā)現(xiàn)①和②中的內(nèi)容,就是之前不用andThen方法,我們自己進(jìn)行調(diào)用的過程

  6.以上分析,仍然是按照面向?qū)ο笾蟹椒ㄕ{(diào)用的思路展開的,但實(shí)質(zhì)上,我們要注意,Function接口中的andThen方法,返回的是一個(gè)Function,里面采用的是lambda表達(dá)式,其實(shí)是在做函數(shù)模型的拼接,把兩個(gè)函數(shù)模型fun1和fun2拼接出一個(gè)新的模型,返回新的模型。所以fun1.andThen(fun2)是把fun1和fun2拼接成一個(gè)新的Function,返回的是lambda表達(dá)式的形式

  最后調(diào)用accept(s)方法時(shí),其實(shí)執(zhí)行的是lambda表達(dá)式{}中的代碼

  4. Predicate接口

  有時(shí)候我們需要對某種類型的數(shù)據(jù)進(jìn)行判斷,從而得到一個(gè)boolean值結(jié)果。這時(shí)可以使用`java.util.function.Predicate`接口。

  4.1.抽象方法:test

  `Predicate`接口中包含一個(gè)抽象方法:`boolean test(T t)`。用于條件判斷的場景:

```java
//1.練習(xí):判斷字符串長度是否大于5
//2.練習(xí):判斷字符串是否包含"H"
public class Demo10Predicate {
    public static void main(String[] args) {
        String str = "helloWorld";
        //1.練習(xí):判斷字符串長度是否大于5
        //lambda標(biāo)準(zhǔn)格式
        fun(str,(String s)->{return s.length()>5;});
        System.out.println("-----------------");

        //2.練習(xí):判斷字符串是否包含"H"
        //lambda標(biāo)準(zhǔn)格式
        fun(str,(String s)->{return s.contains("H");});
       
    }
    /*
        定義一個(gè)方法,參數(shù)是Predicate接口
     */
    public static void fun(String s,Predicate<String>predicate) {
        boolean result = predicate.test(s);
        System.out.println(result);
    }
}
```

  條件判斷的標(biāo)準(zhǔn)是傳入的Lambda表達(dá)式邏輯,只要字符串長度大于5則認(rèn)為很長。

  4.2.默認(rèn)方法:and

  既然是條件判斷,就會(huì)存在與、或、非三種常見的邏輯關(guān)系。其中將兩個(gè)`Predicate`條件使用“與”邏輯連接起來實(shí)現(xiàn)“**并且**”的效果時(shí),可以使用default方法`and`。其JDK源碼為:

```java
default Predicate<T> and(Predicate<? super T> other) {
    Objects.requireNonNull(other);
    return (t) -> test(t) && other.test(t);
}
```

  代碼示例:

  判斷一個(gè)字符串既要包含大寫“H”,又要包含大寫“W”

```java
public class Demo11Predicate {
    public static void main(String[] args) {
        String str = "HelloWorld";
        //1.練習(xí):判斷一個(gè)字符串既要包含大寫“H”,又要包含大寫“W”
        //lambda標(biāo)準(zhǔn)格式
        fun1(str,(String s)->{return s.contains("H");},(String s)->{return s.contains("W");});
        System.out.println("------------");
        fun2(str,(String s)->{return s.contains("H");},(String s)->{return s.contains("W");});
    }

    /*
        演示and方法
        需要兩個(gè)Predicate作為參數(shù)
        fun1方法沒有使用and方法,就是p1和p2分別調(diào)用test方法,
        然后把結(jié)果進(jìn)行&&運(yùn)算--其實(shí)這是and方法的底層實(shí)現(xiàn)
     */
    public static void fun(String s,Predicate<String> p1,Predicate<String> p2) {
        //先判斷一次
        boolean result1 = p1.test(s);
        //再判斷一次
        boolean result2 = p2.test(s);
        //進(jìn)行&&運(yùn)算
        boolean result = result1&&result2;
        System.out.println(result);      
    }
    /*
        演示and方法
        需要兩個(gè)Predicate作為參數(shù)
        
     */
    public static void fun2(String s,Predicate<String> p1,Predicate<String> p2) {
        boolean result = p1.and(p2).test(s);
        System.out.println(result);
    }
}

```

  4.3.默認(rèn)方法:or

  與`and`的“與”類似,默認(rèn)方法`or`實(shí)現(xiàn)邏輯關(guān)系中的“**或**”。JDK源碼為:

```java
default Predicate<T> or(Predicate<? super T> other) {
    Objects.requireNonNull(other);
    return (t) -> test(t) || other.test(t);
}
```

  代碼示例:

  字符串包含大寫H或者包含大寫W”

```java
public class Demo12Predicate {
    public static void main(String[] args) {
        String str = "Helloworld";
        //1.練習(xí):判斷一個(gè)字符串包含大寫“H”或者包含大寫“W”
        //lambda標(biāo)準(zhǔn)格式
        fun1(str,(String s)->{return s.contains("H");},(String s)->{return s.contains("W");});
        System.out.println("------------");
        fun2(str,(String s)->{return s.contains("H");},(String s)->{return s.contains("W");});
    }

    /*
        演示or方法
        需要兩個(gè)Predicate作為參數(shù)
        fun1方法沒有使用or方法,就是p1和p2分別調(diào)用test方法,
        然后把結(jié)果進(jìn)行||運(yùn)算--其實(shí)這是or方法的底層實(shí)現(xiàn)
     */
    public static void fun(String s,Predicate<String> p1,Predicate<String> p2) {
        //先判斷一次
        boolean result1 = p1.test(s);
        //再判斷一次
        boolean result2 = p2.test(s);
        //進(jìn)行||運(yùn)算
        boolean result = result1||result2;
        System.out.println(result);      
    }
    /*
        演示or方法
        需要兩個(gè)Predicate作為參數(shù)
        
     */
    public static void fun2(String s,Predicate<String> p1,Predicate<String> p2) {
        boolean result = p1.or(p2).test(s);
        System.out.println(result);
    }
}

```

  關(guān)于and和or方法的原理,可以參考andThen方法原理

  4.4.默認(rèn)方法:negate

  “與”、“或”已經(jīng)了解了,剩下的“非”(取反)也會(huì)簡單。默認(rèn)方法`negate`的JDK源代碼為:

```java
default Predicate<T> negate() {
    return (t) -> !test(t);
}
```

  從實(shí)現(xiàn)中很容易看出,它是執(zhí)行了test方法之后,對結(jié)果boolean值進(jìn)行“!”取反而已。一定要在`test`方法調(diào)用之前調(diào)用`negate`方法,正如`and`和`or`方法一樣:

```java
import java.util.function.Predicate;

public class Demo13Predicate {
    private static void method(Predicate<String> predicate,String str) {
        boolean veryLong = predicate.negate().test(str);
        System.out.println("字符串很長嗎:" + veryLong);
    }

    public static void main(String[] args) {
        method(s -> s.length() < 5, "Helloworld");
    }
}
```

  
       五、總結(jié)

  本文通過具體的例子,演示了函數(shù)式接口的定義和使用。以及常用的函數(shù)式接口。并給出了相關(guān)的練習(xí)題目。對于部分函數(shù)式接口中的默認(rèn)方法,進(jìn)行了圖解分析,讓你更加深刻的理解函數(shù)式接口的思想和目的。在以后實(shí)際的編程過程中,對于集合的操作,可以通過Stream流完成,而Stream流中的很多方法的參數(shù)都是函數(shù)式接口,通過本文的學(xué)習(xí),你已經(jīng)掌握了函數(shù)式接口的使用,相信后面學(xué)習(xí)Stream流是非常容易的。

分享到:
在線咨詢 我要報(bào)名
和我們在線交談!