326. Java Stream API - 实现自定义的 toList() 与 toSet() 收集器

文章目录

  • [326. Java Stream API - 实现自定义的 `toList()` 与 `toSet()` 收集器](#326. Java Stream API - 实现自定义的 toList()toSet() 收集器)
    • [📦 实现一个自定义 `toList()` 收集器](#📦 实现一个自定义 toList() 收集器)
    • [🚀 使用我们的 `ToList` 收集器](#🚀 使用我们的 ToList 收集器)
    • [🔄 将其改造成 `toSet()` 收集器](#🔄 将其改造成 toSet() 收集器)
      • [✅ 修改 1:使用 `HashSet` 作为容器](#✅ 修改 1:使用 HashSet 作为容器)
      • [✅ 修改 2:声明该收集器是无序的](#✅ 修改 2:声明该收集器是无序的)
    • [🧪 `ToSet` 收集器完整实现示例](#🧪 ToSet 收集器完整实现示例)
    • [🎯 总结一下关键点](#🎯 总结一下关键点)
    • [🧠 小贴士](#🧠 小贴士)

326. Java Stream API - 实现自定义的 toList()toSet() 收集器

在 Java 的 Stream API 中,Collectors.toList()Collectors.toSet() 是最常见的两个内置收集器。但你是否好奇它们背后的原理?今天我们就带大家手动实现一个行为等同于 toList() 的收集器 ,并了解如何基于它改造为 toSet() 收集器。


📦 实现一个自定义 toList() 收集器

java 复制代码
class ToList<T> implements Collector<T, List<T>, List<T>> {

    @Override
    public Supplier<List<T>> supplier() {
        return ArrayList::new; // 创建一个空的 ArrayList 作为中间容器
    }

    @Override
    public BiConsumer<List<T>, T> accumulator() {
        return Collection::add; // 将元素累加到 List 中
    }

    @Override
    public BinaryOperator<List<T>> combiner() {
        return (list1, list2) -> {
            list1.addAll(list2); // 合并两个 List(用于并行流)
            return list1;
        };
    }

    @Override
    public Function<List<T>, List<T>> finisher() {
        return Function.identity(); // 直接返回中间容器,不需要额外转换
    }

    @Override
    public Set<Characteristics> characteristics() {
        return Set.of(Characteristics.IDENTITY_FINISH); // 说明 finisher 是 identity
    }
}

🚀 使用我们的 ToList 收集器

java 复制代码
Collection<String> strings = List.of("one", "two", "three", "four", "five");

List<String> result = strings.stream()
    .collect(new ToList<>()); // 使用我们自定义的收集器

System.out.println("result = " + result);

💡 输出结果:

java 复制代码
result = [one, two, three, four, five]

🔄 将其改造成 toSet() 收集器

我们只需要修改两处,就能实现一个等价于 Collectors.toSet() 的收集器:

✅ 修改 1:使用 HashSet 作为容器

java 复制代码
public Supplier<Set<T>> supplier() {
    return HashSet::new;
}

✅ 修改 2:声明该收集器是无序的

java 复制代码
public Set<Characteristics> characteristics() {
    return Set.of(
        Characteristics.IDENTITY_FINISH,
        Characteristics.UNORDERED // 不保证处理顺序
    );
}

🧪 ToSet 收集器完整实现示例

java 复制代码
class ToSet<T> implements Collector<T, Set<T>, Set<T>> {

    @Override
    public Supplier<Set<T>> supplier() {
        return HashSet::new;
    }

    @Override
    public BiConsumer<Set<T>, T> accumulator() {
        return Set::add;
    }

    @Override
    public BinaryOperator<Set<T>> combiner() {
        return (set1, set2) -> {
            set1.addAll(set2);
            return set1;
        };
    }

    @Override
    public Function<Set<T>, Set<T>> finisher() {
        return Function.identity();
    }

    @Override
    public Set<Characteristics> characteristics() {
        return Set.of(
            Characteristics.IDENTITY_FINISH,
            Characteristics.UNORDERED
        );
    }
}

🎯 总结一下关键点

元素 toList() toSet()
容器类型 ArrayList HashSet
是否无序 ❌(有序) ✅(无序)
特性声明 IDENTITY_FINISH IDENTITY_FINISH, UNORDERED

🧠 小贴士

  • 想提升性能? 在能接受无序的场景中使用 UNORDERED
  • 想避免不必要的转换?AR 类型一致时,记得声明 IDENTITY_FINISH
  • 并行流支持? 如果想支持并行执行,还可以考虑加入 CONCURRENT 特性(配合线程安全结构)。
相关推荐
用户128526116022 小时前
我把祖传Java项目重构后,接口响应从3s砍到了200ms,只改了这几行代码
java
Linsk2 小时前
组件 = 模板 + 业务逻辑
java·前端·vue.js
星沉远浦3 小时前
用Gemini高效解决Java代码报错难以定位的问题
java
用户298698530146 小时前
Word 文档字符级格式化:Java 实现方案详解
java·后端
笨鸟飞不快7 小时前
从单个服务到集群:一次完整的性能排查复盘
java·前端
荣码7 小时前
用Streamlit给AI应用套个界面,10行代码出Web页面
java·python
SamDeepThinking7 小时前
Java微服务练习方式
java·后端·微服务
朦胧之17 小时前
AI 编程-老项目改造篇
java·前端·后端
程序猿大帅1 天前
别再只当调包侠了:用 Spring AI 落地 Function Calling,我被大模型硬生生砸出了三个大坑
java
程序员晓琪1 天前
约定大于配置:基于 Java 包名自动生成 API 版本路由的最佳实践
java·spring boot·后端