栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java8中的函数式接口Supplier、Consumer、BiConsumer详解

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java8中的函数式接口Supplier、Consumer、BiConsumer详解

目录

一、什么是函数式接口?

二、函数式接口应用实战

1. BiConsumer接口和Consumer接口

1) accept(T t,U u)方法 

2) andThen(BiConsumer)方法 

2. Supplier接口

3. Supplier接口和Consumer接口结合应用实战

1) 定义of()方法创建类的对象

2) 定义with()回调属性赋值

3) 定义build()方法开始回调

4) 测试 

5) 调用过程解读 

6) 完整代码 


函数式编程是JDK1.8的新特性,函数式接口是函数式编程主要的体现,在有些情况下我们可以用lambda表达式替代函数式接口传参。

        首先使用hashmap的computeIfAbsent方法举个栗子,该方法的作用是从hashmap中根据key获取一个值,如果没有值, 那么就给该key填充一个值。

   Map userMap = new HashMap<>();
        Integer value = userMap.computeIfAbsent("1", new Function() {
            @Override
            public Integer apply(String s) {
                return 1;
            }
        });

         我们可以看到Funtion接口以参数的形式传给了computeIfAbsent方法,在apply()方法里Return了1, 得到value的值为1,因为computeIfAbsent方法在get一个不存在的key时,会通过接口对象来调用apply()方法,然后将apply()方法的结果返回并将key和value存入到map里。

    default V computeIfAbsent(K key,
            Function mappingFunction) {
        Objects.requireNonNull(mappingFunction);
        V v;
        if ((v = get(key)) == null) {
            V newValue;
            if ((newValue = mappingFunction.apply(key)) != null) {
                put(key, newValue);
                return newValue;
            }
        }

        return v;
    }

        使用lambda表达式替换,结果是一样的:

package func;

import java.util.HashMap;
import java.util.Map;

public class FunctionTests {


    public static void main(String[] args) {
        Map userMap = new HashMap<>();
        Integer value = userMap.computeIfAbsent("1", s -> 1);
        if (userMap.get("1").equals(value)) {
            System.out.println("yes!");
        }

    }
}

  

        lamda表达式看起来更简洁一点。

一、什么是函数式接口?

函数式接口是java8中新加入的一批接口,他们由@FutionalInterface注解标记的接口,我们可以在rt.jar包下的java.util.function包里找到有很多函数式接口,比如常用的函数式接口有Function、Supplier、consumer和Prdicate等。

可以发现,函数式接口里只允许一个抽象方法,我们也可以通过@FunctionalInterface注解自定义一个函数式接口。

@FunctionalInterface
public interface Function0 {

    T get();
    
}

如果包含多个抽象方法,那么会出现报错的提示:

二、函数式接口应用实战

1. BiConsumer接口和Consumer接口

        BiConsumer定义了两个泛型类型T和R,分别做为accept()方法的参数类型,BiConsumer支持2个参数。

@FunctionalInterface
public interface BiConsumer {

    
    void accept(T t, U u);

    
    default BiConsumer andThen(BiConsumer after) {
        Objects.requireNonNull(after);

        return (l, r) -> {
            accept(l, r);
            after.accept(l, r);
        };
    }
}

1) accept(T t,U u)方法 

        accept方法能接受2个类型的参数,例如我们可以在accept方法里写一些逻辑,利用参数t和u做一些事情:

package java8.func;


import java.util.function.BiConsumer;


public class BiConsumerTests {

    static class Record {

        private final BiConsumer biConsumer;


        // 初始化biConsumer
        public Record(BiConsumer biConsumer) {
            this.biConsumer = biConsumer;
        }


        // 调用accept方法
        public void consume(T t, R r) {
            biConsumer.accept(t, r);
        }

        private Integer value;

        public Integer getValue() {
            return value;
        }

        public void setValue(Integer value) {
            this.value = value;
        }
    }

    public static void main(String[] args) {
        Record record = new Record<>((k, v) -> {
            System.out.println(k+","+v);
        });
        record.consume("1", 1);

    }
}

 打印结果: 

2) andThen(BiConsumer)方法 

        super表示下限的类型,extends 表示上限的类型,参数1 至少为T类型或者为T类型的父类,参数2为U类型或者U类型的父类。andThen方法表示会继承当前BiConsumer继续调用下一个BiConsumer里的accept()方法。

        下面使用andThen 结合accept实现一个广播功能,一次Accept,多个注册的consumer都能收到消息。

package java8.func;


import java.util.function.BiConsumer;


public class BiConsumerTests {

    static class Record {

        private final BiConsumer biConsumer;

        private Record next;


        // 初始化biConsumer
        public Record(BiConsumer biConsumer) {
            this.biConsumer = biConsumer;
        }


        // 调用accept方法,多个biConsumer
        public void consume(T t, R r) {
            //当前
            BiConsumer chainConsumer = this.biConsumer;
            while (this.next != null) {
                chainConsumer = chainConsumer.andThen(this.next.biConsumer);
                next = next.next;
            }
            chainConsumer.accept(t, r);
        }

        public void addLast(BiConsumer biConsumer) {
            // 遍历链表到表尾
            Record current=this;
            while (current.next != null) {
                current = current.next;
            }
            current.next = new Record<>(biConsumer);
        }


        private Integer value;

        public Integer getValue() {
            return value;
        }

        public void setValue(Integer value) {
            this.value = value;
        }
    }

    public static void main(String[] args) {
        Record record = new Record<>((k, v) -> {
            System.out.println(k + "," + v);
        });

        record.addLast((k, v) -> {
            System.out.println(k + "-" + v);
        });

        record.addLast((k, v) -> {
            System.out.println(k + "+" + v);
        });
        record.consume("1", 1);

    }
}

打印结果:

        BiConsumer和Consumer区别在于Accept方法入参的个数,consumer里的accept方法只支持一个T类型的参数。

2. Supplier接口

        Supplier接口比consumer接口要更简单点,只有一个get()方法,该方法没有任何参数,也没有andThen,可以通过Supplier给一个类里的属性进行初始化,如下通过supplier给一个List进行初始化。

package java8.func;

import java.util.Arrays;
import java.util.List;
import java.util.function.Supplier;

public class SupplierTests {


    static class Record {


        private final Supplier> supplier;


        public Record(Supplier> supplier) {
            this.supplier = supplier;
        }


        public List getAllRecords() {
            return supplier.get();
        }
    }

    public static void main(String[] args) {


        Record record = new Record<>(() -> Arrays.asList(1, 2, 3, 4, 5));
        List records = record.getAllRecords();
        System.out.println(records);
    }
}

打印结果: 

3. Supplier接口和Consumer接口结合应用实战

        我们可以利用Supplier和Consumer接口编写一个类的初始化工具类,用一行代码去替代不断的set属性。

1) 定义of()方法创建类的对象

        通过supplier将类的对象给保存下来。

    public static  GenericBuilder of(Supplier type) {
        return new GenericBuilder<>(type);
    }

2) 定义with()回调属性赋值

         这里用一个List去保存所有的with,就是说类的属性有多个赋值。

    // T 为类的对象,U为值的属性的
    public  GenericBuilder with(BiConsumer biConsumer, U value) {
        //这一行代码为什么要这样写? 因为我们可以先将用accept方法将Consumer放入到typeModifier列表里
        //当 调用tConsumer.accept(typeInstance)时, typeInstance对象会传入到每一个consumer的accept方法里
        // 调用了biConsumer.accept(t,value)方法,就相当于调用了user.setUserName("bing"), user.setPassWord(bing)方法

//        Consumer tConsumer =new Consumer() {
//            @Override
//            public void accept(T t) {
//                biConsumer.accept(t,value);
//            }
//        };
        Consumer tConsumer = t -> biConsumer.accept(t, value);
        this.typeModifier.add(tConsumer);
        return this;
    }

3) 定义build()方法开始回调

        因为我们用set方法去赋值时,需要用到的是同一个对象,因此我们可以把supplier传入给tConsumer.accept()方法。

  public T build() {
        T typeInstance = this.type.get();
        // 给所有的consumer
        this.typeModifier.forEach(tConsumer -> {
            tConsumer.accept(typeInstance);
        });
        this.typeModifier.clear();
        return typeInstance;
    }

4) 测试 
package java8.func;

import java.util.function.BiConsumer;

public class TypeBuilderTest {

    static class User {

        private Integer id;
        private String userName;

        public Integer getId() {
            return id;
        }

        public void setId(Integer id) {
            this.id = id;
        }

        public String getUserName() {
            return userName;
        }

        public void setUserName(String userName) {
            this.userName = userName;
        }

        @Override
        public String toString() {
            return "User{" +
                    "id=" + id +
                    ", userName='" + userName + ''' +
                    '}';
        }
    }

    public static void main(String[] args) {
//        User user = TypeBuilder.of(User::new)
//                .with(User::setId, 1)
//                .with(User::setUserName, "bing")
//                .build();

        User user = TypeBuilder.of(User::new)
                .with(new BiConsumer() {
                    @Override
                    public void accept(User user, Integer integer) {
                        user.setId(integer);
                    }
                }, 1)
                .with(User::setUserName, "bing")
                .build();
        System.out.println(user);
    }
}

打印结果: 

可以发现我们只需要不停的with就可以实现频繁的with赋值了,是不是变的更简介了! 

5) 调用过程解读 

6) 完整代码 
package java8.func;

import java.util.ArrayList;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Supplier;

public class TypeBuilder {

    private final Supplier type;

    private List> typeModifierLists = new ArrayList<>();

    public TypeBuilder(Supplier type) {
        this.type = type;
    }


    public static  TypeBuilder of(Supplier type) {
        return new TypeBuilder(type);
    }

    //将属性设置组装成Consumer。
    public  TypeBuilder with(BiConsumer biConsumer, U value) {
//        Consumer consumer = t -> biConsumer.accept(t, value);
        Consumer consumer = new Consumer() {
            @Override
            public void accept(T t) {
                // 回调目标方法
                biConsumer.accept(t, value);
            }
        };
        this.typeModifierLists.add(consumer);
        return this;
    }


    public T build() {
        T type = this.type.get();
        // 将type传给所有的consumer, consumer接收到type后,执行biConsumer.accept(t,value), 然后回调setUserName。
//        this.typeModifierLists.forEach(tConsumer -> tConsumer.accept(type));
        this.typeModifierLists.forEach(new Consumer>() {
            @Override
            public void accept(Consumer tConsumer) {
                tConsumer.accept(type);
            }
        });
        this.typeModifierLists.clear();
        return type;
    }


}

转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号