Java 中的 Consumer 与 Supplier 接口

异同分析

Consumer 和 Supplier 是 Java 8 引入的两个重要函数式接口,位于 java.util.function 包中,用于支持函数式编程范式。

相同点

  1. 都是函数式接口(只有一个抽象方法)
  2. 都位于 java.util.function 包中
  3. 都用于 Lambda 表达式和方法引用
  4. 都在 Stream API 和 Optional 类中广泛使用

不同点

特性 Consumer Supplier
方法签名 void accept(T t) T get()
参数 接受一个输入参数 无输入参数
返回值 无返回值 返回一个值
主要用途 消费数据 提供数据
类比 方法中的参数 方法中的返回值

详细分析与使用场景

Consumer 接口

Consumer 表示接受单个输入参数但不返回结果的操作。

java 复制代码
import java.util.function.Consumer;
import java.util.Arrays;
import java.util.List;

public class ConsumerExample {
    public static void main(String[] args) {
        // 基本用法
        Consumer<String> printConsumer = s -> System.out.println(s);
        printConsumer.accept("Hello Consumer!");
        
        // 方法引用方式
        Consumer<String> methodRefConsumer = System.out::println;
        methodRefConsumer.accept("Hello Method Reference!");
        
        // 集合遍历中的应用
        List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
        names.forEach(printConsumer);
        
        // andThen 方法组合多个 Consumer
        Consumer<String> upperCaseConsumer = s -> System.out.println(s.toUpperCase());
        Consumer<String> decoratedConsumer = s -> System.out.println("*** " + s + " ***");
        
        Consumer<String> combinedConsumer = upperCaseConsumer.andThen(decoratedConsumer);
        combinedConsumer.accept("functional interface");
        
        // 在 Optional 中的使用
        java.util.Optional<String> optional = java.util.Optional.of("Present");
        optional.ifPresent(combinedConsumer);
    }
}

Consumer 的使用场景

  1. 遍历集合元素并执行操作
  2. 处理数据并产生副作用(如打印、保存到数据库)
  3. 在 Optional 中处理可能存在的值
  4. 组合多个操作形成处理链

Supplier 接口

Supplier 表示一个供应商,不需要传入参数但返回一个值。

java 复制代码
import java.util.function.Supplier;
import java.util.List;
import java.util.Random;
import java.util.stream.Stream;

public class SupplierExample {
    public static void main(String[] args) {
        // 基本用法
        Supplier<String> stringSupplier = () -> "Hello from Supplier!";
        System.out.println(stringSupplier.get());
        
        // 方法引用方式
        Supplier<Double> randomSupplier = Math::random;
        System.out.println("Random number: " + randomSupplier.get());
        
        // 对象工厂
        Supplier<List<String>> listSupplier = () -> java.util.Arrays.asList("A", "B", "C");
        System.out.println("List from supplier: " + listSupplier.get());
        
        // 延迟计算/初始化
        Supplier<ExpensiveObject> expensiveObjectSupplier = () -> {
            System.out.println("Creating expensive object...");
            return new ExpensiveObject();
        };
        
        System.out.println("Supplier created but no object yet...");
        // 只有在调用 get() 时才会创建对象
        ExpensiveObject obj = expensiveObjectSupplier.get();
        
        // 在 Stream 中生成无限流
        Supplier<Integer> randomIntSupplier = () -> new Random().nextInt(100);
        Stream.generate(randomIntSupplier)
              .limit(5)
              .forEach(System.out::println);
              
        // 在 Optional 中作为备选值
        java.util.Optional<String> emptyOptional = java.util.Optional.empty();
        String value = emptyOptional.orElseGet(() -> "Default from supplier");
        System.out.println("Value from empty optional: " + value);
    }
    
    static class ExpensiveObject {
        ExpensiveObject() {
            // 模拟耗时操作
            try { Thread.sleep(1000); } catch (InterruptedException e) {}
        }
    }
}

Supplier 的使用场景

  1. 延迟初始化或延迟计算
  2. 提供配置或默认值
  3. 生成测试数据或模拟对象
  4. 在 Optional 中提供备选值
  5. 创建对象工厂
  6. 实现惰性求值模式

实际应用示例

下面是一个结合使用 Consumer 和 Supplier 的示例:

java 复制代码
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.logging.Logger;

public class CombinedExample {
    private static final Logger logger = Logger.getLogger(CombinedExample.class.getName());
    
    public static void main(String[] args) {
        // 创建一个数据处理器,结合了 Supplier 和 Consumer
        processData(
            () -> { // Supplier - 提供数据
                // 模拟从数据库或API获取数据
                return new String[] {"Data1", "Data2", "Data3"};
            },
            data -> { // Consumer - 处理数据
                for (String item : data) {
                    System.out.println("Processing: " + item);
                }
            },
            error -> { // Consumer - 错误处理
                logger.severe("Error occurred: " + error.getMessage());
            }
        );
    }
    
    public static <T> void processData(Supplier<T> dataSupplier, 
                                      Consumer<T> dataProcessor, 
                                      Consumer<Exception> errorHandler) {
        try {
            T data = dataSupplier.get(); // 从Supplier获取数据
            dataProcessor.accept(data);  // 用Consumer处理数据
        } catch (Exception e) {
            errorHandler.accept(e);      // 用Consumer处理错误
        }
    }
}

总结

  • Consumer 用于表示接受输入并执行操作但不返回结果的函数,常见于需要处理数据并产生副作用的场景
  • Supplier 用于表示无需输入但返回结果的函数,常见于延迟计算、提供数据和工厂模式场景
  • 两者都是函数式编程中的重要构建块,可以组合使用创建灵活的数据处理管道
  • 在 Stream API、Optional 和现代 Java 框架中广泛应用

理解这两个接口的差异和适用场景有助于编写更简洁、更表达力的 Java 代码,特别是在使用 Stream API 和函数式编程范式时。

相关推荐
lUie INGA1 天前
在2023idea中如何创建SpringBoot
java·spring boot·后端
geBR OTTE1 天前
SpringBoot中整合ONLYOFFICE在线编辑
java·spring boot·后端
Porunarufu1 天前
博客系统UI自动化测试报告
java
Aurorar0rua1 天前
CS50 x 2024 Notes C - 05
java·c语言·数据结构
Cosmoshhhyyy1 天前
《Effective Java》解读第49条:检查参数的有效性
java·开发语言
布谷歌1 天前
常见的OOM错误 ( OutOfMemoryError全类型详解)
java·开发语言
eLIN TECE1 天前
springboot和springframework版本依赖关系
java·spring boot·后端
老神在在0011 天前
Spring Bean 的六种作用域详解
java·后端·spring
仙草不加料1 天前
互联网大厂Java面试故事实录:三轮场景化技术提问与详细答案解析
java·spring boot·微服务·面试·aigc·电商·内容社区