理解 SupplierConsumer 接口的本质与实战意义,将帮你构建更灵活、更优雅的数据处理模型。

一、背景

1. 概述

Java 8 引入的函数式接口为编程范式带来了革命性突破,其中 SupplierConsumer 占据核心地位。二者分别封装了“数据供给”与“数据消费”的逻辑,极大增强了代码的解耦性、可读性和可维护性。

2. 概念类比

可将 SupplierConsumer 类比为“数据处理流水线”的两个节点:

接口 类比角色 描述
Supplier 原料输出端 无需输入,提供数据
Consumer 加工车间 接收输入,执行处理

这种“生产者-消费者”模型在计算机科学中广泛存在。


二、Supplier 接口

1. 接口定义

@FunctionalInterface
public interface Supplier<T> {
    T get();
}
  • 无输入,返回一个 T 类型的结果。

  • 常用于延迟计算、懒加载、数据源抽象等场景。

2. 典型应用场景

✅ 场景一:延迟初始化
private HeavyObject heavyObject;
private final Supplier<HeavyObject> supplier = () -> new HeavyObject();

public HeavyObject getHeavyObject() {
    if (heavyObject == null) {
        heavyObject = supplier.get();
    }
    return heavyObject;
}

✅ 场景二:随机数据生成

Supplier<Integer> RANDOM_SUPPLIER = () -> new Random().nextInt(100);
Stream.generate(RANDOM_SUPPLIER).limit(5).forEach(System.out::println);

✅ 场景三:策略化数据提供

DataProvider provider = new DataProvider(() -> "Data from Cache");
System.out.println(provider.fetchData()); // 输出:Data from Cache

三、Consumer 接口

1. 接口定义

@FunctionalInterface
public interface Consumer<T> {
    void accept(T t);

    default Consumer<T> andThen(Consumer<? super T> after) {
        return (T t) -> { accept(t); after.accept(t); };
    }
}
  • 接收一个输入,无返回值。

  • 常用于日志打印、状态变更、消息推送等“副作用”处理。

2. 典型应用场景

✅ 场景一:打印或格式化输出
Consumer<String> print = System.out::println;
Consumer<String> format = s -> System.out.println("Formatted: " + s.toUpperCase());
print.andThen(format).accept("hello");

✅ 场景二:集合批量处理

List<Integer> numbers = Arrays.asList(1, 2, 3);
numbers.forEach(n -> System.out.print(n + " ")); // 输出:1 2 3

✅ 场景三:对象属性修改

Consumer<User> nameUpdater = u -> u.setName("李四");
Consumer<User> ageUpdater = u -> u.setAge(u.getAge() + 5);
nameUpdater.andThen(ageUpdater).accept(user);

四、Supplier 与 Consumer 的对比分析

维度 Supplier Consumer
核心职责 提供数据(生产者) 处理数据(消费者)
方法签名 T get() void accept(T t)
输入参数 有一个参数
返回值 有(T类型) 无(void)
应用场景 延迟加载、数据生成 打印、修改对象、数据落库
函数组合 不支持组合 支持 andThen()
线程安全 通常线程安全 需注意副作用引起的线程安全问题


五、与匿名内部类的对比

实现方式 Supplier 示例 Consumer 示例
匿名类 new Supplier<String>() { public String get() { return "x"; }} new Consumer<String>() { public void accept(String s) { }}
Lambda () -> "x" s -> System.out.println(s)
方法引用 LocalDate::now System.out::println

优势: 代码量减少 60%+,表达更直观,可组合、可复用。

六、在设计模式中的应用

1. 策略模式

new PriceCalculator(() -> 100.0, price -> System.out.println("VIP价: " + price * 0.8)).calculate();

2. 观察者模式

EventPublisher<String> publisher = new EventPublisher<>();
publisher.register(e -> System.out.println("Log: " + e));
publisher.register(e -> { if (e.contains("error")) System.out.println("Alert!"); });

3. 适配器模式

public class LegacyAdapter implements Supplier<String> {
    private LegacyService legacyService;
    public String get() { return legacyService.fetchData(); }
}

七、实际业务场景应用

✅ 场景:电商订单处理

Supplier<String> ORDER_ID_SUPPLIER = () -> "ORD-" + System.currentTimeMillis();

Consumer<Order> VALIDATE = order -> {
    if (order.getProducts().isEmpty()) throw new IllegalArgumentException("不能为空");
};

Consumer<Order> SAVE = order -> System.out.println("保存订单: " + order.getOrderId());
Consumer<Order> NOTIFY = order -> System.out.println("通知用户: " + order.getOrderId());

// 组合处理流水线
Consumer<Order> orderPipeline = VALIDATE.andThen(SAVE).andThen(NOTIFY);

八、总结与延展

  • SupplierConsumer 是函数式接口体系中的代表,一个用于“数据提供”,一个用于“数据处理”。

  • 它们在业务逻辑抽象、函数组合、设计模式实现等方面都有巨大价值。

📌 延伸建议

  • 探索 Function<T, R>Predicate<T> 接口的组合使用

  • 学习如何在 Spring、RxJava、Reactor 中应用函数式接口

  • 结合 Stream API 构建复杂的数据转换流程

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐