bifunction是java 8引入的函数式接口,用于接收两个参数并返回一个结果,适用于二元变换场景(如合并对象、构造键等),但不适用于对称运算或有副作用的操作。

BiFunction 是什么,什么时候该用它
BiFunction 是 Java 8 引入的函数式接口,位于 java.util.function 包中。它明确表示“接收两个参数、返回一个结果”的纯计算逻辑,适合替代手写单方法接口或匿名类,尤其在需要传递二元变换行为时(比如合并两个对象、计算两数比值、构造带上下文的键等)。
它不是万能工具:如果两个参数类型相同且语义对称(如加法),BinaryOperator<t></t> 更贴切;如果涉及副作用(如写日志、改状态),优先考虑普通方法而非函数式抽象。
如何声明和实现 BiFunction 实例
直接使用 Lambda 最简洁,前提是参数类型和返回类型能被编译器推断:
BiFunction<string integer string> prefixer = (s, len) -> s.substring(0, Math.min(s.length(), len));</string>
注意三点:
- 类型参数顺序必须是
<t u r></t>,对应第一个参数、第二个参数、返回值 - Lambda 参数列表必须恰好两个,且顺序不能颠倒
- 如果需复用或逻辑复杂,可用方法引用:
BiFunction<map object>, String, Object> getter = Map::get</map>
常见踩坑:泛型擦除与 null 安全
BiFunction 本身不约束参数或返回值是否可为 null,但实际使用中容易触发 NPE:
- 第一个参数为
null时调用apply()不报错,但后续逻辑可能崩 - 类型擦除导致无法在运行时校验泛型,比如误传
Integer给期望String的位置,编译期不报错但运行时报ClassCastException
建议:
- 在 Lambda 内部主动判空,或用
Objects.requireNonNull()明确失败点 - 避免将
BiFunction作为公共 API 的参数类型,除非调用方明确知晓契约;内部流转更安全 - 不要试图用
BiFunction, ?, ?>做泛型通配——它几乎无法安全调用apply()
和 Stream 配合时的典型用法
Stream 本身不直接消费 BiFunction,但它常用于构建中间操作所需的辅助逻辑,例如:
- 用
Collectors.toMap(keyMapper, valueMapper, mergeFunction)中的mergeFunction参数就是BiFunction<v></v> - 构造自定义
Collector时,combiner通常为BiFunction<a></a>
Map<string integer> counts = list.stream()
.collect(Collectors.toMap(
s -> s,
s -> 1,
(v1, v2) -> v1 + v2 // 这里 v1/v2 类型一致,本质是 BinaryOperator
));</string>
关键点在于:别硬套 BiFunction 到所有双参数场景,先看目标 API 是否真正接受它——很多地方其实要的是 BinaryOperator 或自定义函数接口。
泛型边界、null 处理、API 接口匹配这三处最容易出问题,写完记得用真实数据跑一遍 apply(),别只看编译通过。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











