Java8 函数式接口Function大家族

Posted by 杨青波 on 2021-06-01

关于Java8 function 包中系列接口的简介

Java8 中在 java.util.function 包中定义了一系列的函数式接口,主要包含五大类:
- Function: 函数接口,主要作用是定义一个类似method的函数(用来代替匿名内部类最合适不过了),给定入参,返回出参,理论上以下四个function的功能都可以用Function接口实现,所以它是一种很综合全面的接口
- Predicate: 断言接口,主要作用是提供校验相关的功能,返回结果为boolean
- Consumer: 消费者模式接口, 主要是给定入参,消费入参,无返回结果集
- Supplier: 生产者模式接口,主要是产生结果,无入参,返回结果为产出
- *Operator: 计算模式接口,继承自Function,这里我们不详解它。主要是提供一些计算和转化功能,分为一元和二元计算,一元计算指给定一个入参,返回一个计算结果,二元计算指给定两个入参,返回一个计算结果
这里注意在function包中命名中带有 Bi 的说明这是一个二元计算,即接受两个参数,返回一个结果(可以理解为Spark中行动算子的概念)

Function 系列接口

Function 系列接口主要是提供类似java 中 method 的函数功能,接受入参返回一个结果,理论上可以使用Function接口完成其他四类functions的功能
主要包含

  • Function<T,R> 接受一个入参T, 返回一个结果 R
  • BiFunction<T,U,R> 接受两个入参 T & U, 返回一个结果 R
  • DoubleFunction<R> 接受一个 double 类型入参,返回一个结果 R
  • DoubleToIntFunction 接受一个 double 类型入参, 返回一个 int 结果
    以下接口不再赘述
    DoubleToLongFunction, IntFunction<R>, IntToDoubleFunction, IntToLongFunction, LongFunction<R>, LongToDoubleFunction, LongToIntFunction, ToDoubleBiFunction<T,U>, ToDoubleFunction<T>, ToIntBiFunction<T,U>, ToLongBiFunction<T,U>, ToLongFunction<T>

所有Function系列接口,围绕

  1. compose() 前置组合函数,可以理解为aop中的before()操作,会将compose的结果传递给apply()函数,多个compose()会按相对顺序顺序执行
  2. apply() 核心函数,可以理解为aop中的被代理的对象,做核心处理逻辑,一个Function接口必须有这个函数,代表核心处理逻辑,apply()函数只能有一个,在compose()后,andThen()前执行
  3. andThen() 后置组合函数,可以理解为aop的after()操作,接收apply()的结果。
    三个方法展开,执行顺序是compose() => apply() => andThen()

Predicate 系列接口

Predicate 系列接口主要是提供断言功能,用来检查参数,验证结果等,接受一个入参返回一个布尔值
主要包含

  • Predicate<T> 接受一个参数 T,返回一个布尔值
  • BiPredicate<T,U> 接受两个参数 T & U,返回一个布尔值
    以下接口不再赘述
    DoublePredicate, IntPredicate, LongPredicate

所有Predicate 系列接口,围绕

  1. test() 核心函数,完成Predicate的核心断言逻辑
  2. and() 功能等于 && ,将两个test()函数进行 && 操作
  3. or() 功能等于 || ,将两个test()函数进行 || 操作
  4. negate() 功能等于 !, 将test()取反 => !test()
    四个方法展开

Consumer 系列接口

Consumer 系列接口主要是提供消费者功能,接受参数并消费,没有返回值
主要包含

  • Consumer<T> 接受一个参数 T, 没有返回值
  • BiConsumer<T,U> 接受两个参数 T & U, 没有返回值
    以下接口不再赘述
    DoubleConsumer, IntConsumer, LongConsumere, ObjDoubleConsumer<T>, ObjIntConsumer<T>, ObjLongConsumer<T>
    所有Comsumer 系列接口,围绕
  1. accept() 接受参数并消费
  2. andThen() 这里的andThen()FunctionandThen()有所不同,FunctionandThen()会将上一个结果传递给下一个,而ConsumerandThen()会将传入的参数多次消费。

Suppiler系列接口

Supplier 系列接口主要是提供生产者功能,不接受参数,返回一个结果
主要包含

  • Supplier<T> 不接受参数,返回一个生产结果,
    以下接口不再赘述
    BooleanSupplier, DoubleSupplier, IntSupplier, LongSupplier

所有Supplier系列接口,围绕

  1. get()/ getAsBoolean()等方法展开, 全部是提供一个返回结果

代码演示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
public class FunctionDemo {
public static void main(String[] args) {
// 定义一个生产者方法,创建一个FunctionDemo对象
Supplier<String> builder = () -> "里奥";
String named = builder.get();
System.out.println("起名" + named);
System.out.println("==============================================================================");


// 定义一个函数,功能是 给定你名字什么,返回全名
Function<String, String> fullName = lastName -> lastName + "梅西";
// 给名字后面加个 ·
Function<String, String> printLastName = firstName -> {
System.out.println("大家叫他小名: " + firstName);
return firstName + "·";
};
// 输出全名
Function<String, String> printFullName = name -> {
System.out.println("我的全名是: " + name);
return name;
};
//多个andThen,compose,执行顺序:(排列时注意andThen和andThen之间的相对顺序, compose和compose之间的相对顺序)
// 1. 多个compose按照顺序执行
// 2. 再执行apply
// 3. 最后andThen按照顺序执行
fullName.andThen(printFullName)
.compose(printLastName)
.andThen((n -> {
System.out.println(n + "长到3岁了");
return n;
}))
.andThen(n -> {
System.out.println(n + "长到10岁了");
return n;
})
.apply(named);
System.out.println("==============================================================================");


// 定义一个断言方法, 判断这个名字包含 liao
String liao = "里奥";
String messi = "梅西";
String testName = "球王梅西";
Predicate<String> liaoPredicate = name -> name.contains(liao);
boolean isLiao = liaoPredicate.test(testName);
// 等于反过来的断言 == !Predicate.test(String string);
Predicate<String> negate = liaoPredicate.negate();
boolean notLiao = negate.test(testName);
System.out.println(testName + "名字含有" + liao + ": test:" + isLiao + "\t negate:" + notLiao + "\t");
Predicate<String> isMessi = name -> name.contains(messi);
// and()同时满足两个断言
boolean isLiaoMessi = liaoPredicate.and(isMessi).test(testName);
System.out.println(testName + "名字既含有里奥也含有梅西: " + isLiaoMessi);
// or() 满足其中一个断言
boolean isLiaoOrMessi = liaoPredicate.or(isMessi).test(testName);
System.out.println(testName + "名字含有里奥或者梅西: " + isLiaoOrMessi);

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

// 定义一个消费者方法,给定一个名字,输出问候语
Consumer<String> consumer = name -> System.out.println(name + "高考报名");
Consumer<String> consumer1 = name -> System.out.println(name + " 第一天考语文");
Consumer<String> consumer2 = name -> System.out.println(name + " 第二天考数学");
Consumer<String> consumer3 = name -> System.out.println(name + " 第三天考英语");
Consumer<String> consumer4 = name -> System.out.println(name + " 第四天考理综");
// 多个 andThen 本身执行是按照顺序的, 但是andThen一定会在accept后面执行, 下面 Function 多个 andThen, compose 同理,
consumer.andThen(consumer1).andThen(consumer2).andThen(consumer3).andThen(consumer4).accept("里奥·梅西");

System.out.println("==============================================================================");
BiFunction<List<Integer>, Integer, Integer> sumTotal = (summaries, integration) -> {
int sum = summaries.stream().mapToInt(Integer::intValue).sum() + integration;
System.out.println("语数外加理综一共总分:" + sum);
return sum;
};

Integer finalTotal = sumTotal.andThen(total -> {
int totalWithExtra = total + 20;
System.out.println("获得世界级奖杯,额外加20分,当前总分:" + totalWithExtra);
return totalWithExtra;
}).apply(Arrays.asList(100, 130, 90), 180);
System.out.println("最终里奥·梅西高考成绩为:" + finalTotal);
}
}

总结

function包可以大量用于可扩展的框架中,丰富框架的扩展性和延展性,让自定义处理函数更广泛的使用。
函数式接口很好的代替了闭包和匿名内部类,并且提供链式调用,所以实际使用中我们会将多个操作用转换成多个andThen等来连接多个操作,最终让代码的流程和可读性更高。
其中function包在java8中的CompletableFuture中得到大量的使用,并且大大简化了java繁琐的异步编程能力,让java也能写出易读的异步代码。



支付宝打赏 微信打赏

赞赏一下