Java中Consumer的andThen方法可将日志记录、指标上报等副作用操作串联成链式调用,实现解耦、可复用、易测试的处理流程。

Java 中可以通过 Consumer 的 andThen 方法将多个日志记录、指标上报等副作用操作串联成链式调用,实现解耦、可复用、易测试的处理流程。
用 andThen 实现链式消费
Consumer<t></t> 接口定义了 void accept(T t) 和默认方法 andThen(Consumer super T> after)。后者返回一个新的 Consumer,先执行当前逻辑,再执行传入的 after 操作,天然支持串行副作用组合。
- 每次调用
andThen都生成新实例,不改变原对象,符合函数式不可变原则 - 所有 Consumer 共享同一输入参数(如事件对象、请求上下文),适合“一次输入、多阶段处理”场景
- 顺序严格:前一个执行完才触发下一个,适合有依赖关系的日志+指标上报
典型组合:日志 + 指标 + 异常兜底
假设有一个订单创建事件 OrderEvent,需同时记录业务日志、上报 Prometheus 指标、并捕获异常防止链路中断:
Consumer<OrderEvent> logConsumer = event ->
log.info("Order created: id={}, amount={}", event.getId(), event.getAmount());
Consumer<OrderEvent> metricConsumer = event -> {
orderCreatedCounter.increment();
orderAmountSummary.record(event.getAmount());
};
Consumer<OrderEvent> safeConsumer = event -> {
try {
logConsumer.andThen(metricConsumer).accept(event);
} catch (Exception e) {
log.error("Failed to process OrderEvent {}", event.getId(), e);
fallbackMetricCounter.increment();
}
};
这里没有手动拼接逻辑,而是通过 andThen 声明式组合,后续还可继续追加审计、消息投递等 Consumer。
立即学习“Java免费学习笔记(深入)”;
进阶:动态组合与条件分支
实际中常需按环境或业务类型分流。可用工厂方法构建 Consumer 链:
- 用
Consumer::andThen动态拼接,例如根据event.getEnv()决定是否启用 debug 日志 - 用
Consumer<T> empty = t -> {}占位,避免空指针;用Objects.requireNonNull校验关键环节 - 对分支逻辑(如支付成功 vs 失败)分别定义 Consumer,再用三元表达式选择:
event.isSuccess() ? successChain : failureChain
注意事项与优化点
Consumer 链本质是同步串行执行,要注意:
- 避免在链中做阻塞 I/O(如远程 HTTP 调用),否则拖慢整个链;应转为异步提交(如发到内存队列+后台线程消费)
- 不要在
andThen中抛出受检异常,否则需包装为 RuntimeException 或改用自定义函数接口 - 链过长时建议提取命名变量(如
monitoringPipeline),提升可读性和复用性 - 单元测试时可分别验证每个 Consumer 行为,并用
ArgumentCaptor检查调用顺序和参数


















