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。
  • ✅ 想避免不必要的转换? 当 A 和 R 类型一致时,记得声明 IDENTITY_FINISH。
  • ✅ 并行流支持? 如果想支持并行执行,还可以考虑加入 CONCURRENT 特性(配合线程安全结构)。
相关推荐
不是万能的豆学长1 小时前
filetidy 文件整理助手:一键归类 + 规范重命名(Python 零依赖单文件工具)
大数据·开发语言·python·技术美术
时间静止不是简史1 小时前
生产事故排查:Redis 宕机导致补偿队列消费线程死亡,通话录音未上送业务平台
java·redis
2301_32241428044 小时前
基于SpringBoot+Vue的休闲零食超市管理系统的设计与实现59004-计算机毕设 原创(免费领源码+部署教程+开发环境)
java·vue.js·spring boot·redis·mysql·决策树·推荐算法
懂点Tech5 小时前
ctfshow MISC入门图片篇(信息附加):misc41解题思路
开发语言·python
金銀銅鐵6 小时前
[Java] 用 GUI 展示 EnumSet 增减元素时的内部变化(上)
java·后端·ai编程
catchadmin6 小时前
PHP 8.7 协程新提案 让跨协程代码共享请求身份
开发语言·php
福建佰胜张工7 小时前
SMC 薄型气爪 MHF2-16D1 深度解析:平行开闭、低剖面结构在自动化装配中的选型与落地
java·服务器·安全·自动化
念何架构之路7 小时前
go-grpc设计思想
开发语言·后端·golang
catoop7 小时前
API Key 设计与安全生成方案:结构拆解、数据库设计与 Java 实现
java·数据库·安全
system_error_x7 小时前
SpringBoot 集成 Thymeleaf 简洁入门
java·spring boot·后端