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

Java8中的函数式接口Supplier、Consumer、BiConsumer详解目录一 什么是函数式接口 二 函数式接口应用实战 1 BiConsumer 接口和 Consumer 接口 1 accept T t U u 方法 2 andThen BiConsumer 方法 2 Supplier 接口 3

大家好,欢迎来到IT知识分享网。

目录

一、什么是函数式接口?

二、函数式接口应用实战

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<String, Integer> userMap = new HashMap<>(); Integer value = userMap.computeIfAbsent("1", new Function<String, Integer>() { @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<? super K, ? extends V> 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<String, Integer> userMap = new HashMap<>(); Integer value = userMap.computeIfAbsent("1", s -> 1); if (userMap.get("1").equals(value)) { System.out.println("yes!"); } } } 
Java8中的函数式接口Supplier、Consumer、BiConsumer详解

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

一、什么是函数式接口?

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

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

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

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

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

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

二、函数式接口应用实战

1. BiConsumer接口和Consumer接口

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

@FunctionalInterface public interface BiConsumer<T, U> { / * Performs this operation on the given arguments. * * @param t the first input argument * @param u the second input argument */ void accept(T t, U u); / * Returns a composed {@code BiConsumer} that performs, in sequence, this * operation followed by the {@code after} operation. If performing either * operation throws an exception, it is relayed to the caller of the * composed operation. If performing this operation throws an exception, * the {@code after} operation will not be performed. * * @param after the operation to perform after this operation * @return a composed {@code BiConsumer} that performs in sequence this * operation followed by the {@code after} operation * @throws NullPointerException if {@code after} is null */ default BiConsumer<T, U> andThen(BiConsumer<? super T, ? super U> 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; / * 测试java.uti.function.BiConsumer接口 */ public class BiConsumerTests { static class Record<T, R> { private final BiConsumer<T, R> biConsumer; // 初始化biConsumer public Record(BiConsumer<T, R> 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<String, Integer> record = new Record<>((k, v) -> { System.out.println(k+","+v); }); record.consume("1", 1); } } 
Java8中的函数式接口Supplier、Consumer、BiConsumer详解

2) andThen(BiConsumer<? super T,? super U>)方法

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

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

package java8.func; import java.util.function.BiConsumer; / * 测试java.uti.function.BiConsumer接口 */ public class BiConsumerTests { static class Record<T, R> { private final BiConsumer<T, R> biConsumer; private Record<T, R> next; // 初始化biConsumer public Record(BiConsumer<T, R> biConsumer) { this.biConsumer = biConsumer; } // 调用accept方法,多个biConsumer public void consume(T t, R r) { //当前 BiConsumer<T, R> chainConsumer = this.biConsumer; while (this.next != null) { chainConsumer = chainConsumer.andThen(this.next.biConsumer); next = next.next; } chainConsumer.accept(t, r); } public void addLast(BiConsumer<T, R> biConsumer) { // 遍历链表到表尾 Record<T,R> 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<String, Integer> 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); } } 

打印结果:

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

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

2. Supplier接口

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

package java8.func; import java.util.Arrays; import java.util.List; import java.util.function.Supplier; public class SupplierTests { static class Record<T> { private final Supplier<List<T>> supplier; public Record(Supplier<List<T>> supplier) { this.supplier = supplier; } public List<T> getAllRecords() { return supplier.get(); } } public static void main(String[] args) { Record<Integer> record = new Record<>(() -> Arrays.asList(1, 2, 3, 4, 5)); List<Integer> records = record.getAllRecords(); System.out.println(records); } } 

打印结果:

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

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

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

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

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

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

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

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

 // T 为类的对象,U为值的属性的 public <U> GenericBuilder<T> with(BiConsumer<T, U> biConsumer, U value) { //这一行代码为什么要这样写? 因为我们可以先将用accept方法将Consumer放入到typeModifier列表里 //当 调用tConsumer.accept(typeInstance)时, typeInstance对象会传入到每一个consumer的accept方法里 // 调用了biConsumer.accept(t,value)方法,就相当于调用了user.setUserName("bing"), user.setPassWord(bing)方法 // Consumer<T> tConsumer =new Consumer<T>() { // @Override // public void accept(T t) { // biConsumer.accept(t,value); // } // }; Consumer<T> 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<User, Integer>() { @Override public void accept(User user, Integer integer) { user.setId(integer); } }, 1) .with(User::setUserName, "bing") .build(); System.out.println(user); } } 

打印结果:

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

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

5)调用过程解读

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

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<T> { private final Supplier<T> type; private List<Consumer<T>> typeModifierLists = new ArrayList<>(); public TypeBuilder(Supplier<T> type) { this.type = type; } public static <T> TypeBuilder<T> of(Supplier<T> type) { return new TypeBuilder<T>(type); } //将属性设置组装成Consumer。 public <U> TypeBuilder<T> with(BiConsumer<T, U> biConsumer, U value) { // Consumer<T> consumer = t -> biConsumer.accept(t, value); Consumer<T> consumer = new Consumer<T>() { @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<Consumer<T>>() { @Override public void accept(Consumer<T> tConsumer) { tConsumer.accept(type); } }); this.typeModifierLists.clear(); return type; } } 

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/94060.html

(0)
上一篇 2024-10-28 14:33
下一篇 2024-10-28 17:26

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

关注微信