一、前言
在实际开发中,我们总会遇到一些特殊场景:比如需要接收两个参数、需要对同一类型数据进行运算、需要避免装箱拆箱开销……这时候,四大核心接口就不够用了。
本篇文章将会讲四大核心接口的升级版—— 常用扩展函数式接口。这些接口都是基于四大核心接口延伸而来,完全贴合生产场景,高频使用且实用性极强,学会它们,就能彻底搞定Java函数式接口的所有常用场景,不用再重复自定义接口。
二、扩展接口的核心逻辑
在讲具体接口之前,先搞懂一个核心逻辑:所有扩展函数式接口,本质都是四大核心接口的补充,没有新增复杂逻辑,只是针对特定场景做了优化,比如:
核心接口只能接收1个参数 → 扩展接口支持接收2个参数(Bi系列);
核心接口的输入和输出类型可以不同 → 扩展接口强制输入和输出类型相同(Operator系列);
核心接口使用包装类型(Integer、Long等) → 扩展接口使用原生类型(int、long等),避免装箱拆箱开销(原生类型系列)。
记住这个逻辑,学习扩展接口就会非常轻松——本质是核心接口的场景化优化,不用重新记全新的逻辑。
三、Bi系列接口
Bi是“Binary”(二元)的缩写,代表“接收两个参数”。Bi系列接口对应三大核心接口(Consumer、Function、Predicate),没有BiSupplier(因为Supplier无参,双参无意义),共3个常用接口,是生产中最高频的扩展接口。
1、BiConsumer<T, U>:双参消费者
1.核心定位
对应核心接口:Consumer<T>(单参无返回)
核心差异: 接收两个参数,无返回值,用于“消费两个数据”的场景(比如修改对象的两个属性、打印两个数据)。
2.核心方法
// 核心抽象方法:接收T、U两个参数,无返回值 void accept(T t, U u); // 常用默认方法:链式消费(先消费t和u,再消费after的accept方法) default BiConsumer<T, U> andThen(BiConsumer<? super T, ? super U> after) { Objects.requireNonNull(after); return (l, r) -> { accept(l, r); after.accept(l, r); }; }3.实战示例(2个高频场景)
示例1:修改对象的两个属性(最常用)
import java.util.function.BiConsumer; // 复用之前的User类 class User { private String name; private int age; // getter/setter、toString省略 } public class BiConsumerTest { public static void main(String[] args) { User user = new User(); // Lambda实现BiConsumer,接收两个参数(String姓名、int年龄),修改User属性 BiConsumer<User, String> setName = (u, name) -> u.setName(name); BiConsumer<User, Integer> setAge = (u, age) -> u.setAge(age); // 链式调用:先设置姓名,再设置年龄 setName.andThen(setAge).accept(user, "李四", 28); System.out.println(user); // 输出:User(name=李四, age=28) } }示例2:打印两个数据(简化多参数打印)
// Lambda实现BiConsumer,接收两个String参数,打印输出 BiConsumer<String, String> printTwoStr = (str1, str2) -> System.out.println("第一个字符串:" + str1 + ",第二个字符串:" + str2); // 调用accept()方法,传入两个参数 printTwoStr.accept("Hello", "BiConsumer"); // 输出:第一个字符串:Hello,第二个字符串:BiConsumer2、BiFunction<T, U, R>:双参函数
1.核心定位
对应核心接口:Function<T, R>(单参有返回)
核心差异: 接收两个参数,返回一个结果,用于“根据两个数据,转换得到一个新数据”的场景(比如两个数相加、拼接两个字符串)。
2.核心方法
// 核心抽象方法:接收T、U两个参数,返回R类型结果 R apply(T t, U u); // 常用默认方法:链式转换(先执行当前BiFunction,再执行after的apply方法) default <V> BiFunction<T, U, V> andThen(Function<? super R, ? extends V> after) { Objects.requireNonNull(after); return (t, u) -> after.apply(apply(t, u)); }3.实战示例(2个高频场景)
示例1:两个整数相加(基础场景)
<