Java工具类函数式接口传参应遵循“类型明确、职责清晰、避免泄露”原则:优先选用Function、Predicate、Consumer、Supplier等内置接口,按行为语义匹配;多参数用Bi系列,超三参数宜封装对象;方法签名须分离固定上下文与可变行为;禁传this,改传字段、函数或接口方法;异常需显式声明或在契约中明确处理策略。

Java 工具类中规范使用函数式接口传参,核心是“类型明确、职责清晰、避免泄露”。不靠硬塞 this,也不用泛型乱套,而是按行为意图选接口、配参数结构、守契约边界。
按行为语义选内置接口,别自定义除非真必要
Java 8+ 提供的四大核心函数式接口已覆盖绝大多数场景:
-
Function
:有输入、有返回,适合转换类操作(如 String::length、user -> user.getName()) -
Predicate
:只判断,返回 boolean,适合过滤或校验(如 u -> u.isActive()) -
Consumer
:只消费,无返回,适合日志、保存、通知等副作用操作(如 System.out::println) -
Supplier
:无输入、有返回,适合延迟创建或默认值兜底(如 () -> new HashMap())
两个参数?优先用 BiFunction<t u r></t>、BiPredicate<t u></t>;三个及以上参数才考虑自定义(如 TriConsumer<a b c></a>),但更推荐封装为对象降维。
工具类方法签名要体现“固定上下文 + 可变行为”分离
比如一个分页查询工具类,不应写成:
立即学习“Java免费学习笔记(深入)”;
❌ 不推荐public static <t> List<t> queryWithCallback(Class<t> type, Object... args)</t></t></t>
而应写成:
✅ 推荐public static <t> List<t> queryByPage(int page, int size, Function<pagequery list>> queryFunc)</pagequery></t></t>
这里 page 和 size 是固定上下文,queryFunc 是可替换行为——调用方决定“怎么查”,工具类只管“何时查、查几次、怎么分页”。
传参时避免直接传 this,优先传行为而非实例
若工具类需要访问当前对象的状态,不要写成:
❌ 不推荐StringUtils.process(this); // this 可能含敏感字段、生命周期难控
而应提取所需行为或数据:
✅ 推荐- 传具体字段:
StringUtils.process(this.getId(), this.getName()) - 传函数封装逻辑:
StringUtils.process(() -> this.buildLogMessage()) - 传接口实现(如当前类实现
Identifiable):StringUtils.process(this::getId)
这样既解耦,又防止工具类意外修改对象状态或引发循环引用。
异常与执行边界必须在接口契约里显式声明
函数式接口本身不声明受检异常,所以如果行为可能抛出 IOException 等,不能直接用 Consumer<t></t>,而要:
- 自定义接口并声明异常,例如:
@FunctionalInterface interface ThrowingConsumer<t> { void accept(T t) throws Exception; }</t> - 或在工具类文档/注释中明确失败策略:“回调失败不中断主流程,仅记录告警”
- 禁止让 Lambda 内部吞掉关键异常,尤其涉及事务、IO、网络时
契约比语法更重要——调用方要清楚传进去的函数在什么条件下会执行、失败后是否重试、结果要不要校验。


















