![从企业级开发到云原生微服务: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=1739777341-TVpMU8lsnZ94fEIgEKRjAosxHlvcOTDb-0-506b7811eff17bdf5cf3a55d6fc5208c)
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_25_01.jpg?sign=1739777341-FZYtS5pkhBOgFYa9KDYlGamMSLTj2TxV-0-e5f1e5e15c2ab039bfa389f1e2b7cb71)
任意一个只有抽象方法的接口都是函数接口(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=1739777341-OtkIeDXybwmtY0SwHi3unMXu73qEcMSa-0-9cd14fd21d6e86790b12e916ce2e3ae8)
Lambda表达式即为test方法的实现。从test方法的定义可以看出,test方法可接收任意类型的参数T,返回值为boolean类型,可以用下面的表达式定义。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_25_03.jpg?sign=1739777341-Rbzo8pxBXDfr8W8xGOJ9OlyaF89FPP9k-0-417e255cd572e739d3d99d353eff8dca)
根据类型推断可缩写为Predicate<String>emptyPredicate=s->s.isEmpty()。
使用当前Predicate定义,可通过test方法执行。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_26_01.jpg?sign=1739777341-HgUSzvCm8m4m9WA8v1qSeTj4BGYUn5si-0-39dc928b55498333e2a844263bc654e2)
输出的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=1739777341-9uRlU62GQPvScyL09RxV5ZZ5ifr2ndi2-0-2a19d20f2d31c1a78aad03abd1b806d1)
◎and:相当于逻辑运算中的&&。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_26_03.jpg?sign=1739777341-kfDw61lOW0krtp6m2PEUfACyKkkJ5Pih-0-e1d03356628a2cb055e7f6be0ce6f600)
只有在i>0且i<100的情况下,test方法的返回值才为true。
◎or:相当于逻辑运算中的||。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_26_04.jpg?sign=1739777341-FDidmkfxODCOh2YfJURMoehrgVHsrPUo-0-f68b5ee31363928e5dbdb00d64443201)
当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=1739777341-VDRedYxodBmIvytjFqsT7nJuYQyU13xC-0-651cdf687764e4e31dbc21ba5642ffa2)
可修改成下面的样子。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_26_06.jpg?sign=1739777341-11NCQgJ8l6O1mU6wSJqIL4WowRtlFYIa-0-de660c2b4eb706aa6e4a22293275a86a)
◎DoublePredicate:入参为double类型。
◎LongPredicate:入参为long类型。
3.两个参数的Predicate
Java还提供了表示两个入参的Predicate,叫作BiPredicate。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_26_07.jpg?sign=1739777341-9DacZTnCEtlmCjOmkNcdt5rKvxdekn4o-0-9df5680638f31acbe9e201adcb3580e9)
test方法可接收两个入参,类型分别为T和U。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_27_01.jpg?sign=1739777341-q8gIvY8NkCQk1xJXaQafcdGEnX30xy2j-0-150c1e03ef193523c4228b17b2ea71b3)
第一个入参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=1739777341-sQ8LcgptLIVOreC0bXJNWgOMLAxp1oCP-0-e8813dd06e6a4fe3fe477600ff2959da)
Lambda表达式是apply方法的实现,apply方法可接收任意类型的参数T,返回值类型为R,可以用下面的表达式定义。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_27_03.jpg?sign=1739777341-umYpf3OjxITTqOkZFPSxRNimzmFrLk1O-0-e6edc27c7519f6ee2b5947235f541990)
入参T类型为String(str),返回值R类型为Integer(str.length()),使用当前Function定义,可通过apply方法执行。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_27_04.jpg?sign=1739777341-K191Hj4SYy8q6o99C5NYWk48cnOagR7A-0-7acfe1c045ed04f7665b9ad90f8d2682)
输出的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=1739777341-4DP5U7OyzJcPiXngPzgD1Rk7hDaH1sL9-0-4eb31c1598c8d35f9e8e2e8def48cf09)
(1)andThen:新的Function是把组合中第一个函数的返回值作为第二个函数的输入。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_27_06.jpg?sign=1739777341-FlkhmHmtEzlLQihseERF6X1MamnigprS-0-707dbb737ae45274744cb244057d6c75)
执行时,plusFunction先执行,返回值作为multipleFunction的入参再执行,结果为16。
(2)compose:新的Function是把组合中第二个函数的返回值作为第一个函数的输入。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_27_07.jpg?sign=1739777341-WH23QEgP8atf3XwuqD8xjji9t0WPM2cN-0-a37cc0d896a6ab95be3328f874869d8f)
执行时,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=1739777341-uVbjJ73fUQ3ZTk2hG6Oq3edaqJn8EQJD-0-cda8ee06047055d8a6932ec9fae7ec04)
◎LongFunction:入参为long类型。
◎DoubleFunction:入参为double类型。
第二类是返回值固化为函数接口,入参类型T仍需在泛型中定义。
◎ToIntFunction:返回值类型为int类型。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_28_02.jpg?sign=1739777341-ycPpFVs1NpmNxSVqzwI2BhYuoxz7EbFz-0-4bb9b67ec7e5be45b25b3a6abdb99857)
◎ToLongFunction:返回值类型为long类型。
◎ToDoubleFunction:返回值类型为double类型。
第三类是入参和返回值都固化为函数接口。
◎IntToLongFunction:入参为int类型,返回值为long类型。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_28_03.jpg?sign=1739777341-gPiGGAgGGA7VMPnWDaOkYtm9I1NBKkK4-0-caf5cb01981eb5a8d737d84080231ac6)
◎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=1739777341-RqXZz2244xitXfm05BP292JXxSYpZvRk-0-3a30d5b931cb99ddeb83e97ff6e8c737)
apply方法可接收两个参数T和U,返回值为R。可以用下面的表达式定义。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_28_05.jpg?sign=1739777341-5qzyrY0qfRfR77YaD6QuRiYQYWbDUJvL-0-d5661c6996332f8ccaf68b28e7ac0ee7)
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=1739777341-mJxlMr6VfKV3JegwcpTMhlwmhoLT740Z-0-ae8b69686327c7b4db20b6cf2225e84f)
从accept方法的定义中可以看出,accept方法可接收一个参数T,没有返回值,可以用下面的表达式定义。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_29_02.jpg?sign=1739777341-cluwhr6y1CegUHe2ZyJFRKtNoa32twTI-0-f68634a6f02e2b5a8ffda880dfc366a1)
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=1739777341-t5Gu37lxJmlUAncHpPA8Y4HkHAquOVJQ-0-3ab174b83aaf85afb71fcd8780218a9a)
get方法不接收参数,返回值为类型T,可以用下面的表达式定义。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_29_04.jpg?sign=1739777341-P9SWRXETjdOAExAPKhQbvFJER0coBJHc-0-414026455cf17ed45683056574a7d0f9)
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=1739777341-PgOzwudKhAUgl7DmJWm1VQbwVX8YVQeK-0-ed9e7d4a69688684e45b159af1fbefa5)
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=1739777341-bwA6c4mj8UC6XYwdw5E6IjJgf1UJpURw-0-e050167e838338031fc16ae3da8f926a)
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=1739777341-IYejbO8LYt80Hd8WOKeJwjqv1jw8KPVS-0-e9d1d4345c14057ea5eaf6c4bc449cad)
◎若o1小于o2,则返回负数。
◎若o1等于o2,则返回0。
◎若o1大于o2,则返回正数。
可以用Lambda表达式来定义。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_31_01.jpg?sign=1739777341-reMlrJHy8vHTrUHiWtLrOzDKqzRt4kDd-0-9a466448a75f09994d0e8156e3ef3fd3)
Comparator函数接口还为排序提供了comparing的静态方法,它可接收一个Function接口来获取处理数据的排序key,上面的语句可以简写成下面的样子。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_31_02.jpg?sign=1739777341-qifQtMEjs4owKqXGghvKWv8OAD4CqNRd-0-f41797237e07dff1e7bbaad2b573abe3)
2.3.7 自定义函数接口
函数接口的定义主要是看入参和返回值,前面介绍了有一个入参的Function接口和有两个入参的BiFunction接口,下面自定义一个有三个入参的TriFunction接口。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_31_03.jpg?sign=1739777341-8BzTkT0jUHeJHBFsgSiIyut384gNfuaa-0-9324ef3b02ffefc62819e3e10638285f)
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=1739777341-bndBNnkkgpC0gc6BnfiHX0dAJ9tahbl1-0-3fa0090898973bea754d0deb0afe6a77)
第一个入参类型为String(str1),第二个入参类型为String(str2),第三个入参类型为String(str3),返回值类型为Integer。计算输出三个字符串的长度之和,输出结果为9。