天天看點

Java8之Consumer、Supplier、Predicate和Function攻略

  • 2020部落格位址彙總
  • 2019年部落格彙總

轉載:https://www.cnblogs.com/SIHAIloveYAN/p/11288064.html

今天我們還講講Consumer、Supplier、Predicate、Function這幾個接口的用法,在 Java8 的用法當中,這幾個接口雖然沒有明目張膽的使用,但是,卻是潤物細無聲的。為什麼這麼說呢?

這幾個接口都在 

java.util.function

 包下的,分别是Consumer(消費型)、supplier(供給型)、predicate(謂詞型)、function(功能性),相信有了後面的解釋,你應該非常清楚這個接口的功能了。

那麼,下面,我們從具體的應用場景來講講這個接口的用法!

1 Consumer接口

從字面意思上我們就可以看得出啦,

consumer接口

就是一個消費型的接口,通過傳入參數,然後輸出值,就是這麼簡單,Java8 的一些方法看起來很抽象,其實,隻要你了解了就覺得很好用,并且非常的簡單。

我們下面就先看一個例子,然後再來分析這個接口。

1.1 Consumer執行個體

/**
     * consumer接口測試
     */
    @Test
    public void test_Consumer() {
        //① 使用consumer接口實作方法
        Consumer<String> consumer = new Consumer<String>() {

            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        };
        Stream<String> stream = Stream.of("aaa", "bbb", "ddd", "ccc", "fff");
        stream.forEach(consumer);

        System.out.println("********************");

        //② 使用lambda表達式,forEach方法需要的就是一個Consumer接口
        stream = Stream.of("aaa", "bbb", "ddd", "ccc", "fff");
        Consumer<String> consumer1 = (s) -> System.out.println(s);//lambda表達式傳回的就是一個Consumer接口
        stream.forEach(consumer1);
        //更直接的方式
        //stream.forEach((s) -> System.out.println(s));
        System.out.println("********************");

        //③ 使用方法引用,方法引用也是一個consumer
        stream = Stream.of("aaa", "bbb", "ddd", "ccc", "fff");
        Consumer consumer2 = System.out::println;
        stream.forEach(consumer);
        //更直接的方式
        //stream.forEach(System.out::println);
    }
           

輸出結果

Java8之Consumer、Supplier、Predicate和Function攻略

1.2 執行個體分析

① 

consumer

接口分析

在代碼①中,我們直接建立 

Consumer

 接口,并且實作了一個名為 

accept

 的方法,這個方法就是這個接口的關鍵了。

我們看一下 

accept

 方法;這個方法傳入一個參數,不傳回值。當我們發現 

forEach

 需要一個 

Consumer

 類型的參數的時候,傳入之後,就可以輸出對應的值了。

② lambda 表達式作為 consumer

Consumer<String> consumer1 = (s) -> System.out.println(s);//lambda表達式傳回的就是一個Consumer接口
           

在上面的代碼中,我們使用下面的 

lambda

 表達式作為 

Consumer

。仔細的看一下你會發現,

lambda

 表達式傳回值就是一個 

Consumer

;是以,你也就能夠了解為什麼 

forEach

 方法可以使用 lamdda 表達式作為參數了吧。

③ 方法引用作為 consumer

Consumer consumer2 = System.out::println;
           

在上面的代碼中,我們用了一個方法引用的方式作為一個 Consumer ,同時也可以傳給 

forEach

 方法。

1.3 其他 Consumer 接口

除了上面使用的 Consumer 接口,還可以使用下面這些 Consumer 接口。

IntConsumer、DoubleConsumer、LongConsumer、BiConsumer

,使用方法和上面一樣。

1.4 Consumer 總結

看完上面的執行個體我們可以總結為幾點。

① Consumer是一個接口,并且隻要實作一個 

accept

 方法,就可以作為一個“消費者”輸出資訊。

② 其實,lambda 表達式、方法引用的傳回值都是 Consumer 類型,是以,他們能夠作為 

forEach

 方法的參數,并且輸出一個值。

2 Supplier 接口

Supplier 接口是一個供給型的接口,其實,說白了就是一個容器,可以用來存儲資料,然後可以供其他方法使用的這麼一個接口,是不是很明白了,如果還是不明白,看看下面的例子,一定徹底搞懂!

2.1 Supplier執行個體

**
     * Supplier接口測試,supplier相當一個容器或者變量,可以存儲值
     */
    @Test
    public void test_Supplier() {
        //① 使用Supplier接口實作方法,隻有一個get方法,無參數,傳回一個值
        Supplier<Integer> supplier = new Supplier<Integer>() {
            @Override
            public Integer get() {
                //傳回一個随機值
                return new Random().nextInt();
            }
        };

        System.out.println(supplier.get());

        System.out.println("********************");

        //② 使用lambda表達式,
        supplier = () -> new Random().nextInt();
        System.out.println(supplier.get());
        System.out.println("********************");

        //③ 使用方法引用
        Supplier<Double> supplier2 = Math::random;
        System.out.println(supplier2.get());
    }
           

輸出結果

Java8之Consumer、Supplier、Predicate和Function攻略

2.2 執行個體分析

① Supplier接口分析

Supplier<Integer> supplier = new Supplier<Integer>() {
            @Override
            public Integer get() {
                //傳回一個随機值
                return new Random().nextInt();
            }
        };
           

看一下這段代碼,我們通過建立一個 Supplier 對象,實作了一個 

get

 方法,這個方法無參數,傳回一個值;是以,每次使用這個接口的時候都會傳回一個值,并且儲存在這個接口中,是以說是一個容器。

② lambda表達式作為 Supplier

//② 使用lambda表達式,
        supplier = () -> new Random().nextInt();
        System.out.println(supplier.get());
        System.out.println("********************");
           

上面的這段代碼,我們使用 lambda 表達式傳回一個 Supplier類型的接口,然後,我們調用 

get

 方法就可以擷取這個值了。

③ 方法引用作為 Supplier

//③ 使用方法引用
        Supplier<Double> supplier2 = Math::random;
        System.out.println(supplier2.get());
           

方法引用也是傳回一個Supplier類型的接口。

2.3 Supplier 執行個體2

我們看完第一個執行個體之後,我們應該有一個了解了,下面再看一個。

/**
     * Supplier接口測試2,使用需要Supplier的接口方法
     */
    @Test
    public void test_Supplier2() {
        Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);
        //傳回一個optional對象
        Optional<Integer> first = stream.filter(i -> i > 4)
                .findFirst();

        //optional對象有需要Supplier接口的方法
        //orElse,如果first中存在數,就傳回這個數,如果不存在,就放回傳入的數
        System.out.println(first.orElse(1));
        System.out.println(first.orElse(7));

        System.out.println("********************");

        Supplier<Integer> supplier = new Supplier<Integer>() {
            @Override
            public Integer get() {
                //傳回一個随機值
                return new Random().nextInt();
            }
        };

        //orElseGet,如果first中存在數,就傳回這個數,如果不存在,就傳回supplier傳回的值
        System.out.println(first.orElseGet(supplier));
    }
           

輸出結果

Java8之Consumer、Supplier、Predicate和Function攻略

代碼分析

Optional<Integer> first = stream.filter(i -> i > 4)
                .findFirst();
           

使用這個方法擷取到一個 Optional 對象,然後,在 Optional 對象中有 orElse 方法 和 orElseGet 是需要一個 Supplier 接口的。

//optional對象有需要Supplier接口的方法
        //orElse,如果first中存在數,就傳回這個數,如果不存在,就放回傳入的數
        System.out.println(first.orElse(1));
        System.out.println(first.orElse(7));

        System.out.println("********************");

        Supplier<Integer> supplier = new Supplier<Integer>() {
            @Override
            public Integer get() {
                //傳回一個随機值
                return new Random().nextInt();
            }
        };

        //orElseGet,如果first中存在數,就傳回這個數,如果不存在,就傳回supplier傳回的值
        System.out.println(first.orElseGet(supplier));
           
  • orElse:如果first中存在數,就傳回這個數,如果不存在,就放回傳入的數
  • orElseGet:如果first中存在數,就傳回這個數,如果不存在,就傳回supplier傳回的值

2.4 其他 Supplier 接口

除了上面使用的 Supplier 接口,還可以使用下面這些 Supplier 接口。

IntSupplier 、DoubleSupplier 、LongSupplier 、BooleanSupplier

,使用方法和上面一樣。

2.5 Supplier 總結

① Supplier 接口可以了解為一個容器,用于裝資料的。

② Supplier 接口有一個 

get

 方法,可以傳回值。

3 Predicate 接口

Predicate 接口是一個謂詞型接口,其實,這個就是一個類似于 bool 類型的判斷的接口,後面看看就明白了。

3.1 Predicate 執行個體

/**
     * Predicate謂詞測試,謂詞其實就是一個判斷的作用類似bool的作用
     */
    @Test
    public void test_Predicate() {
        //① 使用Predicate接口實作方法,隻有一個test方法,傳入一個參數,傳回一個bool值
        Predicate<Integer> predicate = new Predicate<Integer>() {
            @Override
            public boolean test(Integer integer) {
                if(integer > 5){
                    return true;
                }
                return false;
            }
        };

        System.out.println(predicate.test(6));

        System.out.println("********************");

        //② 使用lambda表達式,
        predicate = (t) -> t > 5;
        System.out.println(predicate.test(1));
        System.out.println("********************");

    }
           

輸出結果

Java8之Consumer、Supplier、Predicate和Function攻略

3.2 執行個體分析

① Predicate 接口分析

//① 使用Predicate接口實作方法,隻有一個test方法,傳入一個參數,傳回一個bool值
        Predicate<Integer> predicate = new Predicate<Integer>() {
            @Override
            public boolean test(Integer integer) {
                if(integer > 5){
                    return true;
                }
                return false;
            }
        };
           

這段代碼中,建立了一個 

Predicate

 接口對象,其中,實作類 

test

 方法,需要傳入一個參數,并且傳回一個 

bool

 值,是以這個接口作用就是判斷!

System.out.println(predicate.test(6));
           

再看,調用 test 方法,傳入一個值,就會傳回一個 bool 值。

② 使用lambda表達式作為 predicate

//② 使用lambda表達式,
        predicate = (t) -> t > 5;
        System.out.println(predicate.test(1));
        System.out.println("********************");
           

lambda 表達式傳回一個 

Predicate

 接口,然後調用 

test

 方法!

3.3 Predicate 接口執行個體2

/**
     * Predicate謂詞測試,Predicate作為接口使用
     */
    @Test
    public void test_Predicate2() {
        //① 将Predicate作為filter接口,Predicate起到一個判斷的作用
        Predicate<Integer> predicate = new Predicate<Integer>() {
            @Override
            public boolean test(Integer integer) {
                if(integer > 5){
                    return true;
                }
                return false;
            }
        };

        Stream<Integer> stream = Stream.of(1, 23, 3, 4, 5, 56, 6, 6);
        List<Integer> list = stream.filter(predicate).collect(Collectors.toList());
        list.forEach(System.out::println);

        System.out.println("********************");

    }
           

輸出結果

Java8之Consumer、Supplier、Predicate和Function攻略

這段代碼,首先建立一個 Predicate 對象,然後實作 

test

 方法,在 test 方法中做一個判斷:如果傳入的參數大于 5 ,就傳回 true,否則傳回 false;

Stream<Integer> stream = Stream.of(1, 23, 3, 4, 5, 56, 6, 6);
        List<Integer> list = stream.filter(predicate).collect(Collectors.toList());
        list.forEach(System.out::println);
           

這段代碼調用 

Stream

 的 

filter

 方法,

filter

 方法需要的參數就是 Predicate 接口,是以在這裡隻要大于 5 的資料就會輸出。

3.4 Predicate 接口總結

① Predicate 是一個謂詞型接口,其實隻是起到一個判斷作用。

② Predicate 通過實作一個 

test

 方法做判斷。

4 Function 接口

Function 接口是一個功能型接口,它的一個作用就是轉換作用,将輸入資料轉換成另一種形式的輸出資料。

4.1 Function 接口執行個體

/**
     * Function測試,function的作用是轉換,将一個值轉為另外一個值
     */
    @Test
    public void test_Function() {
        //① 使用map方法,泛型的第一個參數是轉換前的類型,第二個是轉化後的類型
        Function<String, Integer> function = new Function<String, Integer>() {
            @Override
            public Integer apply(String s) {
                return s.length();//擷取每個字元串的長度,并且傳回
            }
        };

        Stream<String> stream = Stream.of("aaa", "bbbbb", "ccccccv");
        Stream<Integer> stream1 = stream.map(function);
        stream1.forEach(System.out::println);

        System.out.println("********************");

    }
           

輸出結果

Java8之Consumer、Supplier、Predicate和Function攻略

4.2 代碼分析

① Function 接口分析

//① 使用map方法,泛型的第一個參數是轉換前的類型,第二個是轉化後的類型
        Function<String, Integer> function = new Function<String, Integer>() {
            @Override
            public Integer apply(String s) {
                return s.length();//擷取每個字元串的長度,并且傳回
            }
        };
           

這段代碼建立了一個 

Function

 接口對象,實作了一個 

apply

 方法,這個方法有一個輸入參數和一個輸出參數。其中,泛型的第一個參數是轉換前的類型,第二個是轉化後的類型。

在上面的代碼中,就是擷取字元串的長度,然後将每個字元串的長度作為傳回值傳回。

② 重要應用 map 方法

Stream<String> stream = Stream.of("aaa", "bbbbb", "ccccccv");
        Stream<Integer> stream1 = stream.map(function);
        stream1.forEach(System.out::println);

           

在 

Function

 接口的重要應用不得不說 

Stream

 類的 

map

 方法了,

map

 方法傳入一個 

Function

 接口,傳回一個轉換後的 

Stream

類。

4.3 其他 Function 接口

除了上面使用的 Function 接口,還可以使用下面這些 Function 接口。

IntFunction 、DoubleFunction 、LongFunction 、ToIntFunction 、ToDoubleFunction 、DoubleToIntFunction 等等,使用方法和上面一樣。

4.4 Function 接口總結

① Function 接口是一個功能型接口,是一個轉換資料的作用。

② Function 接口實作 

apply

 方法來做轉換。

5 總結

通過前面的介紹,已經對

Consumer、Supplier、Predicate、Function

這幾個接口有詳細的了解了,其實,這幾個接口并不是很難,隻是有點抽象,多加了解會發現很簡單,并且特别好用!

繼續閱讀