consumer更适合做观察者逻辑,因其天然契合“消费一个值、不返回结果”的update语义,可复用jdk接口、消除模板代码、支持lambda与组合操作。

Java 8 的 Consumer<t></t> 接口可以大幅简化观察者模式的实现,把原本需要定义接口、抽象类、多个具体观察者类的繁重结构,压缩为一行 lambda 或方法引用。核心思路是:用 Consumer 替代自定义的 Observer 接口,用函数式表达“收到通知后做什么”,从而消除模板代码和继承层级。
为什么 Consumer 更适合做观察者逻辑
Consumer<t></t> 天然契合观察者行为的本质——它只关心“消费一个值”,不返回结果,正对应 update(T data) 的语义。相比传统 Observer 接口:
- 无需声明新接口,直接复用 JDK 标准函数式接口
- 避免空实现类或匿名内部类的样板代码
- 支持 lambda 表达式,让注册观察者像写一句“收到就打印”一样直观
- 天然支持组合(
andThen)、判空防护(Consumer<t>.accept</t>可配合Objects.requireNonNull)
重构步骤:从传统写法到 Consumer 版本
假设原主题类维护 List<observer></observer> 并调用 observer.update(data)。重构只需三步:
- 将主题内部的观察者集合从
List<observer></observer>改为List<consumer>></consumer>(类型按实际通知数据调整) - 删除所有自定义
Observer接口及其实现类 - 注册时传入
Consumer<string></string>实例,例如system.addSubscriber(s -> log.info("收到: {}", s))
完整示例:气象站通知消费者
传统方式要写 Observer 接口、PhoneDisplay、WebDisplay 等多个类;Consumer 版本只需:
主题类(精简后):
public class WeatherStation {
private final List<consumer>> subscribers = new ArrayList();
private float temperature;
public void register(Consumer<float> subscriber) {
subscribers.add(subscriber);
}
public void setTemperature(float temp) {
this.temperature = temp;
subscribers.forEach(consumer -> consumer.accept(temp));
}
}</float></consumer>
使用时直接传行为:
WeatherStation station = new WeatherStation();
// 手机端:打印温度
station.register(temp -> System.out.println("? 手机显示:" + temp + "℃"));
// 后台告警:温度超阈值发邮件
station.register(temp -> {
if (temp > 40) {
sendAlertEmail("高温预警:" + temp);
}
});
station.setTemperature(38.5f); // 自动触发所有 Consumer
进阶技巧:支持异步与条件过滤
Consumer 本身无执行上下文,但可轻松组合其他工具增强能力:
- 异步通知:用
CompletableFuture.runAsync(() -> consumer.accept(data), executor) - 条件订阅:先
filter再forEach,例如只通知温度变化超过 0.5℃ 的消费者 - 错误隔离:对每个 Consumer 包裹 try-catch,避免单个消费者异常中断整个通知链
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











