BiFunction是Java 8引入的函数式接口,用于两个输入、一个输出的转换场景,声明为BiFunction<T,U,R>,含唯一抽象方法R apply(T t,U u),广泛用于数据合并、Stream/Optional链式调用及结果后处理。

BiFunction 是 Java 8 引入的函数式接口,专为“两个输入、一个输出”的转换或计算场景设计,用起来直接、类型安全,且天然适配 Stream、Optional 等现代 API。
核心写法:定义 + apply 调用
它声明为 BiFunction<T, U, R>,其中 T 和 U 是两个不同(或相同)类型的输入,R 是返回类型。唯一抽象方法是 R apply(T t, U u)。
- 写一个加法器:
BiFunction<Integer, Integer, Integer> add = (a, b) -> a + b;,调用add.apply(3, 7)得到 10 - 拼接字符串:
BiFunction<String, String, String> join = (prefix, suffix) -> prefix + "-" + suffix;,join.apply("user", "123")返回 "user-123" - 构造对象:
BiFunction<String, Integer, Person> builder = Person::new;,前提是 Person 有对应参数的构造器
业务中做双源数据合并转换
当需要把两个不相关的输入“揉在一起”生成新结构时,BiFunction 比写工具方法更清晰、易复用。
- 用用户 ID(String)和缓存 Map(Map<String, User>)查出并封装 VO:
BiFunction<String, Map<String, User>, UserVO> toVo = (id, cache) -> Optional.ofNullable(cache.get(id)).map(UserVO::fromUser).orElse(null); - 把原始金额(BigDecimal)和折扣率(BigDecimal)转成实付金额:
(amt, rate) -> amt.multiply(BigDecimal.ONE.subtract(rate)) - 组合 HTTP 请求头(Map<String, String>)和请求体(OrderDTO),校验后生成上下文对象 Context
配合 Stream 和 Optional 提升表达力
它不是孤立存在的,常嵌入在链式调用中,让逻辑更紧凑。
立即学习“Java免费学习笔记(深入)”;
- Stream.collect 里处理 key 冲突:
Collectors.toMap(k -> k.getId(), v -> v, (v1, v2) -> v1.merge(v2)),第三个参数就是 BiFunction<V,V,V> - Optional 链式取值:
userId.flatMap(id -> userOpt.map(u -> fullNameBiFunc.apply(id, u))),避免层层 if 判空 - 用 andThen 做结果后处理:
BiFunction<Integer, Integer, Integer> sumThenDouble = (a, b) -> a + b; sumThenDouble.andThen(x -> x * 2).apply(4, 6)→ 先得 10,再 ×2 得 20
实用提醒:别踩这几个坑
看似简单,但实际用错容易引发 NPE 或难以调试。
- lambda 里别写多行复杂逻辑;提取成命名方法,比如
(a, b) -> computeWithValidation(a, b),方便单元测试 - 涉及可能为空的参数,提前用
Objects.requireNonNull(a, "a must not be null")防御 - 若内部有 IO 或可能抛异常,不要硬塞进 apply;改用 try-catch 包裹,返回 Optional 或默认值
- 注意和 BinaryOperator 的区别:后者是 BiFunction 的子集,要求 T == U == R,比如
BinaryOperator<Integer> max = Math::max;


















