今天将介绍Java另外两个函数编程接口Consumer、Function,这两个函数是干嘛的呢?先看看官方的定义:
@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); };
}
}
其实Consumer我们经常使用,你看下面这个例子:
List<String> list = Arrays.asList("1", "2", "3");
list.forEach(System.out::println);
我们经常使用的forEach函数其实就是通过Consumer来实现的,所以掌握Consumer很有必要哦,下面看看forEach在ArrayList中的实现:
public void forEach(Consumer<? super E> action) {
Objects.requireNonNull(action);
final int expectedModCount = modCount;
final E[] elementData = (E[]) this.elementData;
final int size = this.size;
for (int i=0; modCount == expectedModCount && i < size; i++) {
action.accept(elementData[i]);
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
}
不用介绍,想必大家也能看的懂,Consumer就表示一个自定义的操作,将该操作作为参数传入到另一个函数内,可在该函数内执行自定义的操作。上面的for循环代码就等同于:
for (int i=0; modCount == expectedModCount && i < size; i++) {
System.out.println(elementData[i]);
}
如果操作比较常用或者通用,可以使用一个类去实现Consumer,保存该操作,在必要的时候能快速使用。
// 实体类
public class Person {
private String name;
private Integer age;
public Person(String name, Integer age) {
this.name = name;
this.age = age;
}
//...
}
// 打印小孩
public class PrintChild implements Consumer<Person> {
@Override
public void accept(Person person) {
if (person.getAge() < 18) {
System.out.println(person.getName() + "还是个孩子啊");
}
}
}
// 测试代码
List<Person> list1 = Arrays.asList(
new Person("大壮", 19),
new Person("小光", 16),
new Person("小小", 15));
list1.forEach(new PrintChild());
函数源码:
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
andThen函数的功能就是将两个Consumer操作合并,并返回一个新的Consumer,使用如下:
// 打印年龄
public class PrintAge implements Consumer<Person> {
@Override
public void accept(Person person) {
System.out.println(person.getName() + "的年龄是:" + person.getAge() + "岁");
}
}
// 测试代码
List<Person> list1 = Arrays.asList(
new Person("小雨", 19),
new Person("小光", 16),
new Person("小小", 15));
list1.forEach(new PrintChild().andThen(new PrintAge()));
// 结果
小雨的年龄是:19岁
小光是个孩子
小光的年龄是:16岁
小小是个孩子
小小的年龄是:15岁
接口名 | 参数 | 返回类型 | 描述 |
---|---|---|---|
BiConsumer | (T, U) | void | BiConsumer接受两个参数 |
DoubleConsumer | double | void | 接受一个double类型的参数 |
IntConsumer | int | void | 接受一个int类型的参数 |
LongConsumer | long | void | 接受一个long类型的参数 |
ObjDoubleConsumer | (T, double) | void | 接受一个Object类型和一个double类型参数 |
ObjIntConsumer | (T, int) | void | 接受一个Object类型和一个int类型参数 |
ObjLongConsumer | (T, long) | void | 接受一个Object类型和一个long类型参数 |
Function和Consumer在功能上是一致的,但是Function有返回结果。
@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;
}
}
Function我们也是会经常使用到的,喏:
List<Person> list1 = Arrays.asList(
new Person("小雨", 19),
new Person("小光", 16),
new Person("小小", 15));
List<String> list = list1.stream()
.map(Person::getName)
.collect(Collectors.toList());
如果你看过笔者写的另一篇文章(重识Java8函数式编程),那么下面的代码你应该也能看得懂,其实上面的map操作可以还原成:
List<String> list = list1.stream()
.map(person -> {
return person.getName();
})
.collect(Collectors.toList());
map内就是封装了一个有返回值的函数,将函数作为参数参入map内。
函数源码:
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
该函数作用就是组合两个Function,参数Function before先执行,执行后的结果交由调用方Function执行。
// 加法
public class AddFunc implements Function<Integer, Integer> {
private int origin;
public AddFunc(int origin) {
this.origin = origin;
}
@Override
public Integer apply(Integer integer) {
return this.origin + integer;
}
}
// 减法
public class ReduceFunc implements Function<Integer, Integer> {
private int origin;
private boolean isMinuend;// origin被减数与否
public ReduceFunc(int origin, boolean isMinuend) {
this.origin = origin;
this.isMinuend = isMinuend;
}
@Override
public Integer apply(Integer integer) {
return isMinuend ? this.origin - integer : integer - this.origin;
}
}
// 测试代码
public class Test {
public static void main(String[] args) {
// 计算 1 + (2 - 3)
System.out.println(handle(new AddFunc(1).compose(new ReduceFunc(2, true)), 3));
}
public static int handle(Function<Integer, Integer> function, Integer integer) {
return function.apply(integer);
}
}
函数源码:
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
andThen函数的作用也是组合两个Function,只不过参数Function后执行。
// 测试代码
public class Test {
public static void main(String[] args) {
// 计算 1 + 2 - 4
System.out.println(handle(new AddFunc(1).andThen(new ReduceFunc(4, false)), 2));
}
public static int handle(Function<Integer, Integer> function, Integer integer) {
return function.apply(integer);
}
}
源码:
static <T> Function<T, T> identity() {
return t -> t;
}
好吧,这个函数的功能就是返回一个输入和输出都一样的Function,那么这个函数有什么用呢?看示例:
// 示例:将list转变为map
List<Person> list = Arrays.asList(
new Person("xiaoxiao", 11),
new Person("dazhuang", 15));
Map<String, Person> map = list.stream()
.collect(Collectors.toMap(Person::getName, person -> person));
// 使用identity函数
List<Person> list = Arrays.asList(
new Person("xiaoxiao", 11),
new Person("dazhuang", 15));
Map<String, Person> map = list.stream()
.collect(Collectors.toMap(Person::getName, Function.identity()));
两种使用方式都是可以的,但是你觉得哪个方式更有魅(bi)力(ge)呢?
运用的基础是先掌握,只有掌握才能熟练运用,干了这杯毒鸡汤。(小声BB:端午最后一天假了,T . T)
接口名 | 参数 | 返回类型 | 描述 |
---|---|---|---|
BiFunction | (T, U) | R | BiFunction接受两个参数 |
DoubleFunction | double | R | 接受一个double类型的参数 |
DoubleToIntFunction | double | int | 接受double类型参数,返回int类型结果 |
DoubleToLongFunction | double | long | 接受double类型参数,返回long类型结果 |
IntFunction | int | R | 接受一个int类型的参数 |
IntToDoubleFunction | int | double | 接受int类型参数,返回double类型结果 |
IntToLongFunction | int | long | 接受int类型参数,返回long类型结果 |
LongFunction | long | R | 接受一个long类型的参数 |
LongToDoubleFunction | long | double | 接受long类型参数,返回double类型结果 |
LongToIntFunction | long | int | 接受long类型参数,返回int类型结果 |
ToDoubleBiFunction | (T, U) | double | 接受两个参数,返回double类型结果 |
ToDoubleFunction | T | double | 接受一个Object类型,返回double类型参数 |
ToIntBiFunction | (T, U) | int | 接受两个参数,返回int类型结果 |
ToIntFunction | T | int | 接受一个Object类型,返回int类型参数 |
ToLongBiFunction | (T, U) | long | 接受两个参数,返回long类型结果 |
ToLongFunction | T | long | 接受一个Object类型,返回long类型参数 |
文章推荐:
【睡JDK】Java函数式编程接口详解之Predicate
【睡JDK】Java函数式编程接口详解之Supplier
【睡JDK】Java函数式编程接口详解之UnaryOperator、BinaryOperator