![从企业级开发到云原生微服务:Spring Boot实战](https://wfqqreader-1252317822.image.myqcloud.com/cover/257/33831257/b_33831257.jpg)
2.3 函数接口
上面的例子中涉及很多函数接口,例如:
◎Function
◎Consumer
◎Comparator
它们都属于函数接口,都标记了@FunctionalInterface注解。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_24_03.jpg?sign=1739277313-TlsbfZiJP3zEPJpBfKHdXdcYuDgHijVC-0-be99af00e898c43d84b27b8f3bfca0ba)
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_25_01.jpg?sign=1739277313-6nVDDMVvK6eAVfoBwJY2x6Xk32L61wye-0-de22cba6084dd0ec96e533c1a4cbaede)
任意一个只有抽象方法的接口都是函数接口(Functional Interface),这类接口都可以使用Lambda表达式(或方法引用)实现。函数接口只有一个抽象方法,但有很多其他方法,这些方法可归类如下。
◎静态方法:和接口有关的工具助手方法。使用static关键字实现。
◎默认方法:添加新的功能方法到已有的接口,在老的代码中,使用了该接口其他方法的代码不会受到影响。使用default关键字实现。
这也意味着从Java 8开始,接口内不仅可以有抽象方法,还可以有静态方法和默认方法。只要符合定义,即使没有标记@FunctionalInterface,它也是函数接口。当然,如果不符合函数接口的定义,那么即使标记了@FunctionalInterface,编译器也会报错,这就是@FunctionalInterface的作用。
函数接口主要位于java.util.function包下,可分成下面几类。
◎Predicate:有输入且只输出布尔值的函数。
◎Function:有输入有输出的函数。
◎Consumer:有输入无输出的函数。
◎Supplier:无输入有输出的函数。
◎Operator:输入和输出为相同类型的函数。
2.3.1 Predicate
Predicate(断言)的源码定义如下。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_25_02.jpg?sign=1739277313-DpIC9nyrMnHSa1TCsedAebouUnUVcpa7-0-b2b598bbc611f32d5507f6561dd8e06a)
Lambda表达式即为test方法的实现。从test方法的定义可以看出,test方法可接收任意类型的参数T,返回值为boolean类型,可以用下面的表达式定义。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_25_03.jpg?sign=1739277313-lUkTOwFS4h3CqLLxkq7LBTNImtyRMuq1-0-7a9fd013183207d2ee4bdfaee78369fc)
根据类型推断可缩写为Predicate<String>emptyPredicate=s->s.isEmpty()。
使用当前Predicate定义,可通过test方法执行。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_26_01.jpg?sign=1739277313-PghUGuJovzKjRcxr4bR0OjMW6XTujZrH-0-58cb8556b0aa8694ef89ed585774cc6e)
输出的emptyPredicate.test("wyf")返回值为false。
1.组合Predicate
Predicate接口包含negate、and和or方法,可以重用已有的Predicate,组成复杂的Predicate。
◎negate:已有Predicate的否定。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_26_02.jpg?sign=1739277313-ayTpL7CTw0r32ojkD5ym8FCBolpHn4Nn-0-bb7f46d9713801ebfcb917bccf303a13)
◎and:相当于逻辑运算中的&&。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_26_03.jpg?sign=1739277313-LTwUgqWBGRLZi8IxhsxSrDKSZEKgRkuM-0-c3a8c7a850f8dd63f8c1d1a3b629bfb0)
只有在i>0且i<100的情况下,test方法的返回值才为true。
◎or:相当于逻辑运算中的||。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_26_04.jpg?sign=1739277313-1QdyzJEqsToe3QmQLp0KCJze7gJ3T2Cz-0-99b9eecf19f65c67b027d9b98904dbfb)
当i>0或i<100时,test方法的返回值是true。
2.原始数据类型Predicate
Java会自动将包装类型拆包成原始数据类型,但这意味着性能的损失,所以当数据为原始数据类型时,Java提供了一些特殊的Predicate。
◎IntPredicate:当入参是int类型时,
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_26_05.jpg?sign=1739277313-FOQWQH3Vr2WNzLG2kchzRWk5eJzC5fby-0-df01a3b41fc4adcd1e956db4488e32ee)
可修改成下面的样子。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_26_06.jpg?sign=1739277313-ygGKF7zDcWujnlp0RV2hRh2vD2OAfmAD-0-898f8d19d35cc6d7662a6b6c9a8e9386)
◎DoublePredicate:入参为double类型。
◎LongPredicate:入参为long类型。
3.两个参数的Predicate
Java还提供了表示两个入参的Predicate,叫作BiPredicate。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_26_07.jpg?sign=1739277313-mTgkR94fp2uzFPFCFLZzuBM1Xo9E2J3U-0-0d4eb317c333ac010c89bd16ae0db5d8)
test方法可接收两个入参,类型分别为T和U。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_27_01.jpg?sign=1739277313-8ZQ8UnhJFsD7WrKN33DrhH7RzOE8FZ0w-0-80a35aee4f44479eff1045f54394989c)
第一个入参T类型为String(str),第二个入参U类型为Integer(len)。
2.3.2 Function
Function(函数)的源码定义如下。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_27_02.jpg?sign=1739277313-F6n3JZHzsgvCVLSmYAdMuadBBsseFC8O-0-42f5fbb173b4fe1450ad5a298651edf1)
Lambda表达式是apply方法的实现,apply方法可接收任意类型的参数T,返回值类型为R,可以用下面的表达式定义。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_27_03.jpg?sign=1739277313-4HC5yKs9jm2lEC0fVxFCbHFqGLafbUWW-0-ecfe6c30d0dccfb751cbebfc30741ea7)
入参T类型为String(str),返回值R类型为Integer(str.length()),使用当前Function定义,可通过apply方法执行。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_27_04.jpg?sign=1739277313-PIO4sZKWjTlpDP6HFs6JmXqKY1vkyvJ6-0-a22b82c70529221b14f703af23920ab5)
输出的lengthFunction.apply("wyf")返回值为3。
1.组合Function
Function接口函数提供了andThen和compose方法来组合已有的Function,组合Function的返回值仍为Function。下面定义两个将被组合的Function。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_27_05.jpg?sign=1739277313-65UKRuJcb6JT7o5QLrjO18wuAmmT9ke3-0-9d5b1e01567769f9a78eccb1abe6f08c)
(1)andThen:新的Function是把组合中第一个函数的返回值作为第二个函数的输入。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_27_06.jpg?sign=1739277313-Q9CKSFrlVq3Ks45M7jrngIM95KsfkUkK-0-199005cf7086651cc152291c0cd32f06)
执行时,plusFunction先执行,返回值作为multipleFunction的入参再执行,结果为16。
(2)compose:新的Function是把组合中第二个函数的返回值作为第一个函数的输入。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_27_07.jpg?sign=1739277313-6HdBsyMY0PvQXrwm1VGQfUhoShZvPAX3-0-8cede35950867560600d9bb54d037171)
执行时,multipleFunction先执行,返回值作为plusFunction的入参再执行,结果为8。
2.原始数据类型Function
与Predicate一样,Function也有原始数据类型的Function,主要有3类。
第一类入参固化为函数接口,返回值类型R,仍需在泛型中定义。
◎IntFunction:入参为int类型。上面的plusFunction可修改为
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_28_01.jpg?sign=1739277313-4NmR11zCZKMZ8AxSdEi2kn8Kx6JmMcu6-0-25be02f3c43881b7329ea10b03ea5919)
◎LongFunction:入参为long类型。
◎DoubleFunction:入参为double类型。
第二类是返回值固化为函数接口,入参类型T仍需在泛型中定义。
◎ToIntFunction:返回值类型为int类型。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_28_02.jpg?sign=1739277313-PI6D3JbktveX2QH5O0Anm8bcWlO3gt8u-0-32d6f364417cbe1b24333627e4e450fe)
◎ToLongFunction:返回值类型为long类型。
◎ToDoubleFunction:返回值类型为double类型。
第三类是入参和返回值都固化为函数接口。
◎IntToLongFunction:入参为int类型,返回值为long类型。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_28_03.jpg?sign=1739277313-PlHBStPAtkToKp6ilP7BpXOb6E2Y5TlI-0-10be9acf1b030d043518fe270792e8f6)
◎IntToDoubleFunction:入参为int类型,返回值为double类型。
◎LongToIntFunction:入参为long类型,返回值为int类型。
◎LongToDoubleFunction:入参为long类型,返回值为double类型。
◎DoubleToIntFunction:入参为double类型,返回值为int类型。
◎DoubleToLongFunction:入参为double类型,返回值为long类型。
3.两个入参的Function
Java还提供了BiFunction,源码定义如下。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_28_04.jpg?sign=1739277313-6drolhWjIlEizU01jbXef7PWe0sz7Ue1-0-3039485625dba8d13c341f6732b898ea)
apply方法可接收两个参数T和U,返回值为R。可以用下面的表达式定义。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_28_05.jpg?sign=1739277313-Re9mUW44UugJfTqCG38AI7gz7Aj0v6E1-0-7a58c6e332220f7e11dca135e64c0b8f)
apply方法的第一个入参T类型是String(str1),第二个入参U类型是String(str2),返回值是两个字符串长度之和。执行apply方法,输出为6。
同样,BiFunction也有很多原始数据类型函数。
◎ToIntBiFunction:返回值为int类型。
◎ToLongBiFunction:返回值为long类型。
◎ToDoubleBiFunction:返回值为double类型。
2.3.3 Consumer
顾名思义,Consumer(消费者)是只消费不生产,源码定义如下。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_29_01.jpg?sign=1739277313-wXKsNzjGI6P4oat3LpMsYE6sVAuw5xOW-0-c5d2c3aeacfde6c15f3d04bd35afe1f0)
从accept方法的定义中可以看出,accept方法可接收一个参数T,没有返回值,可以用下面的表达式定义。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_29_02.jpg?sign=1739277313-naU5UJgVogJoVrvVm5jmr9tImDoccbsx-0-5a0162ae9161e5c06e5a96562dcd8ad3)
accept方法可接收的参数T类型是String(str),没有返回值。
Consumer有原始数据类型接口。
◎IntConsumer:入参为int类型。
◎LongConsumer:入参为long类型。
◎DoubleConsumer:入参为double类型。
Consumer也有表示两个参数的BiConsumer接口。
◎ObjIntConsumer:第一个入参为任意类型T,第二个入参为int类型。
◎ObjLongConsumer第一个入参为任意类型T,第二个入参为long类型。
◎ObjDoubleConsumer:第一个入参为任意类型T,第二个入参为double类型。
2.3.4 Supplier
顾名思义,Supplier(提供者)是只生产不消费,源码定义如下。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_29_03.jpg?sign=1739277313-ZjIIVWremAEAdt6VkRc9TnWj0w7z6HaJ-0-8e668358b1fc9c51fdd81b8cc68061ac)
get方法不接收参数,返回值为类型T,可以用下面的表达式定义。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_29_04.jpg?sign=1739277313-w5eFdnm4qQgXm9rmJ4SpwuZvBzocGj8U-0-2c60b28d4773b4ac77b0e3b328afdad8)
get方法没有入参,返回值是Long类型,输出当前系统事件。
同样,Supplier也有原始数据类型接口。
◎IntSupplier:返回值是int类型。
◎LongSupplier:返回值是long类型。
◎DoubleSupplier:返回值是double类型。
◎BooleanSupplier:返回值是boolean类型。
2.3.5 Operator
Operator(操作者)是一种特殊的Function接口,它的输入和返回值是同一种类型。
1.UnaryOperator
UnaryOperator继承了Function接口,定义如下。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_30_01.jpg?sign=1739277313-AGrbnCJpH9Vo3U64iO7w1KSsnuPHDgZs-0-44a0080f9f37d7483b8454655bef42c3)
UnaryOperator可接收一个入参类型T,返回值也是类型T。
同样,UnaryOperator也有原始数据类型的函数接口。
◎IntUnaryOperator:入参和返回值都是int类型。
◎LongUnaryOperator:入参和返回值都是long类型。
◎DoubleUnaryOperator:入参和返回值都是double类型。
2.BinaryOperator
BinaryOperator继承了Function接口,定义如下。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_30_02.jpg?sign=1739277313-R5hTnSaojCUdlWX4VBgA7wppVtP9de5K-0-242dbd23db7be50368ce632b760b2052)
BinaryOperator接收的两个入参类型都为T,返回值类型也是T。
同样,BinaryOperator也有原始数据类型的函数接口。
◎IntBinaryOperator:两个入参和一个返回值都是int类型。
◎LongBinaryOperator:两个入参和一个返回值都是long类型。
◎DoubleBinaryOperator:两个入参和一个返回值都是double类型。
2.3.6 Comparator
Comparator是比较排序所用的一个函数接口,定义如下。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_30_03.jpg?sign=1739277313-XX5a0ulED5tOi5iBBCvhkggJiWr4XpEt-0-31fea429a2f8db6538d12e27a0e4d1f7)
◎若o1小于o2,则返回负数。
◎若o1等于o2,则返回0。
◎若o1大于o2,则返回正数。
可以用Lambda表达式来定义。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_31_01.jpg?sign=1739277313-IMXxZdAKXm5tUmkYZDAHHCD1Muu7lqwr-0-cad8e37a71abffc465883347d508824a)
Comparator函数接口还为排序提供了comparing的静态方法,它可接收一个Function接口来获取处理数据的排序key,上面的语句可以简写成下面的样子。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_31_02.jpg?sign=1739277313-ZKtkI88HkZWua8cjyefcGcsgcwYCe0B2-0-d670ac5a696529878185e41738f20cb9)
2.3.7 自定义函数接口
函数接口的定义主要是看入参和返回值,前面介绍了有一个入参的Function接口和有两个入参的BiFunction接口,下面自定义一个有三个入参的TriFunction接口。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_31_03.jpg?sign=1739277313-YGLLxAuu5l0Ds4vHczuN1ZQYNtbAvhxM-0-52a534ed5cda8f4333696e5eee19d66d)
a.@FunctionalInterface标记为函数接口。
b.apply方法可接收三个入参T(t)、U(u)和W(w),返回值为R。
可以通过如下Lambda表达式调用。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_31_04.jpg?sign=1739277313-Ux2breFtG43aUA75IJasReZLYukV7g5v-0-7cfd3bc9bf558db6409d8bacb1e3e47f)
第一个入参类型为String(str1),第二个入参类型为String(str2),第三个入参类型为String(str3),返回值类型为Integer。计算输出三个字符串的长度之和,输出结果为9。