接口consumer 、supplier 、predicate 、function

快速理解Consumer、Supplier、Predicate與Function
一、前言
這幾個(gè)接口都處在java.util.function包下,Consumer(消費(fèi)型),Supplier(供給型)、Predicate(判斷型)與Function(轉(zhuǎn)換型),暫時(shí)不理解他們的類(lèi)型沒(méi)關(guān)系。

如果對(duì)Lambda不怎么理解的同學(xué),可以先移步到我的另外一篇文章對(duì)Lambda的理解

二、Consumer
Consumer是一個(gè)消費(fèi)型的接口,它接收一個(gè)西瓜,然后對(duì)這個(gè)西瓜進(jìn)行消費(fèi),連西瓜籽都不帶留下的。

先看Consumer接口的源碼,有一個(gè)未實(shí)現(xiàn)的抽象方法,和一個(gè)默認(rèn)方法(jdk1.8之后,接口里面可以有默認(rèn)方法和靜態(tài)方法)。

@FunctionalInterface
public interface Consumer<T> {
 
    void accept(T t);
 
    default Consumer<T> andThen(Consumer<? super T> after) {
        Objects.requireNonNull(after);
        return (T t) -> { accept(t); after.accept(t); };
    }
 
}

我們只在意這個(gè)accept方法,接收一個(gè)泛型參數(shù),不返回任何值。ok,我們來(lái)簡(jiǎn)單實(shí)現(xiàn)它

        Consumer<Integer> consumer=new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) {
                System.out.println(integer);
            }
        };
 
        consumer.accept(1);
    }

好了,用腳指頭想著,肯定是輸出1了。

接下來(lái)我們使用lambda表達(dá)式來(lái)對(duì)此匿名內(nèi)部類(lèi)進(jìn)行改寫(xiě)。此時(shí)該lambda的類(lèi)型就是Consumer類(lèi)型。

    consumer=i-> System.out.println(i);

當(dāng)然我們也可以使用方法引用

    consumer=System.out::println;

在Stream類(lèi)中,我們發(fā)現(xiàn)常用的forEach接口接收一個(gè)Consumer類(lèi)型的參數(shù),源碼如下

    void forEach(Consumer<? super T> action);

二話不說(shuō),我們將consumer傳入forEach中,來(lái)實(shí)現(xiàn)遍歷集合的操作。

        List<Integer> list= Arrays.asList(1,2,3,4,5);
        Consumer<Integer> consumer= System.out::println;
        list.stream().forEach(consumer);

將中間consumer對(duì)象去掉呢,代碼會(huì)變得更加簡(jiǎn)潔。咦,到這里,是不是有一種似曾相識(shí)的感覺(jué),原來(lái)是這樣演變來(lái)的。

        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
        list.stream().forEach(System.out::println);

Consumer總結(jié):

Consumer接口是一個(gè)消費(fèi)型的接口,只要實(shí)現(xiàn)它的accept方法,就能作為消費(fèi)者來(lái)輸出信息。
lambda、方法引用都可以是一個(gè)Consumer類(lèi)型,因此他們可以作為forEach的參數(shù),用來(lái)協(xié)助Stream輸出信息。
Consumer還有很多變種,例如IntConsumer、DoubleConsumer與LongConsumer等,歸根結(jié)底,這些變種其實(shí)只是指定了Consumer中的泛型而已,方法上并無(wú)變化。
三、Supplier
Supplier是一個(gè)供給型的接口,我們可以無(wú)條件的從它這里獲取東西。

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

我們不需要為get方法傳入任何參數(shù),就能獲得一個(gè)結(jié)果,這不是白嫖嗎?那我想要一個(gè)隨機(jī)數(shù)

        Supplier<Double> supplier=()->new Random().nextDouble();
        //當(dāng)然也可以使用方法引用
        Supplier<Double> supplier1= Math::random;
        System.out.println(supplier.get());

下一步,Supplier可以哪些地方呢,畢竟是可以白嫖的,誰(shuí)不喜歡呢?我們看看Supplier在Optional中的應(yīng)用。

    public T orElseGet(Supplier<? extends T> other) {
        return value != null ? value : other.get();
    }

該方法接收Supplier類(lèi)型的參數(shù),當(dāng)Optional內(nèi)部的value為空時(shí),才會(huì)返回Supplier中的值。例如

        Optional<Double> optional=Optional.empty();
        Supplier<Double> supplier=()->new Random().nextDouble();
        optional.orElseGet(supplier);

這必定返回Supplier中的隨機(jī)值,因?yàn)镺ptional.empty()包含的值就是null。

Supplier總結(jié):

Supplier是一個(gè)供給型的接口,其中的get方法用于返回一個(gè)值。
Supplier也有很多的變種,例如IntSupplier、LongSupplier與BooleanSupplier等
四、Predicate
Predicate是一個(gè)判斷型接口,看看它的源碼。

@FunctionalInterface
public interface Predicate<T> {
 
    boolean test(T t);
 
    default Predicate<T> and(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) && other.test(t);
    }
 
    default Predicate<T> negate() {
        return (t) -> !test(t);
    }
 
    default Predicate<T> or(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) || other.test(t);
    }
 
    static <T> Predicate<T> isEqual(Object targetRef) {
        return (null == targetRef)
                ? Objects::isNull
                : object -> targetRef.equals(object);
    }
}

該接口將jdk1.8中接口的變化體現(xiàn)的淋漓盡致,接口不再“純粹”了,可以有默認(rèn)方法與靜態(tài)方法了,下次面試再問(wèn)道,就得分情況嘍,哭出聲。

要理解一個(gè)接口,我們就去實(shí)現(xiàn)它的方法。

        Predicate<Integer> predicate=i->i>5;
        System.out.println(predicate.test(1));

很明顯,輸出是false。等等,既然可以進(jìn)行判斷,那和Stream.filter()有沒(méi)有關(guān)系呢?

    Stream<T> filter(Predicate<? super T> predicate);

果然是有關(guān)系的,嘖嘖嘖,我這敏銳的嗅覺(jué)。那我們把Predicate對(duì)象傳入filter試試?

        List<Integer> list= Arrays.asList(1,2,3,4,5,6,7,8);
        list.stream().filter(i->i>5).forEach(System.out::print);

很簡(jiǎn)單,輸出是678。

Predicate總結(jié):

Predicate是一個(gè)判斷型的接口,用一個(gè)test方法去測(cè)試傳入的參數(shù)。
當(dāng)然,Predicate也有對(duì)應(yīng)的變種。
五、Function
Function是一個(gè)功能型的接口,用于將一種類(lèi)型的數(shù)據(jù)轉(zhuǎn)化為另外一種類(lèi)型的數(shù)據(jù)。

@FunctionalInterface
public interface Function<T, R> {
 
    R apply(T t);
 
    default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
        Objects.requireNonNull(before);
        return (V v) -> apply(before.apply(v));
    }
 
    default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (T t) -> after.apply(apply(t));
    }
 
    static <T> Function<T, T> identity() {
        return t -> t;
    }
}

重點(diǎn)關(guān)注它的apply方法,現(xiàn)在就去實(shí)現(xiàn)它,并將之傳入進(jìn)Stream.map()方法中試試。

public class TestFunction {
    static class Student{
        String name;
        Integer id;
 
        public Student(String name, Integer id) {
            this.name = name;
            this.id = id;
        }
 
        public String getName() {
            return name;
        }
 
        public Integer getId() {
            return id;
        }
    }
    public static void main(String[] args) {
        List<Student> list= Arrays.asList(new Student("jack",1),new Student("tom",2));
        Function<Student,Integer> function= Student::getId;
        list.stream().map(function).forEach(System.out::print);
    }
    
}

輸出12,可以看得出,F(xiàn)unction中的apply方法將Student類(lèi)型的數(shù)據(jù)轉(zhuǎn)化為對(duì)應(yīng)id的Integer類(lèi)型的數(shù)據(jù)。

Function總結(jié):

Function是一個(gè)轉(zhuǎn)換型的接口,其中的apply可以將一種類(lèi)型的數(shù)據(jù)轉(zhuǎn)化成另外一種類(lèi)型的數(shù)據(jù)。
Function的變種就更多了。
六、總結(jié)
首先只要記住這四個(gè)接口的類(lèi)型,Consumer(消費(fèi)型)、Supplier(供給型)、Predicate(判斷型)與Function(轉(zhuǎn)換型),

再記住他們對(duì)應(yīng)的抽象方法Consumer(accpet)、Supplier(get)、Predicate(test)與Function(apply)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容