324. Java Stream API - 实现 Collector 接口:自定义你的流式收集器

文章目录

  • [324. Java Stream API - 实现 `Collector` 接口:自定义你的流式收集器](#324. Java Stream API - 实现 Collector 接口:自定义你的流式收集器)
    • [🔍 为什么要实现 `Collector` 接口?](#🔍 为什么要实现 Collector 接口?)
    • [☕ 自定义 Collector 的三种方式](#☕ 自定义 Collector 的三种方式)
    • [📐 理解 `Collector<T, A, R>` 的三个类型参数](#📐 理解 Collector<T, A, R> 的三个类型参数)
      • [🚗 举例说明](#🚗 举例说明)
    • [📋 代码示例:查看 `Collector` 类型参数](#📋 代码示例:查看 Collector 类型参数)
    • [🧪 补充示例:自定义 Collector 实现(首字母统计)](#🧪 补充示例:自定义 Collector 实现(首字母统计))
    • [🧠 总结:自定义 Collector 的 5 个核心方法](#🧠 总结:自定义 Collector 的 5 个核心方法)
    • [✅ Collector 特性(`characteristics()`)常见值](#✅ Collector 特性(characteristics())常见值)

324. Java Stream API - 实现 Collector 接口:自定义你的流式收集器

在 Java Stream API 中,Collector 是终端操作 collect() 背后的核心接口。如果你希望完全掌控数据收集的过程------比如构造特定的数据结构、在并行流中定制合并方式等------那就需要了解如何实现这个接口。


🔍 为什么要实现 Collector 接口?

虽然大多数时候我们可以使用 Java 提供的标准收集器(如 toList()groupingBy()joining()),但当你需要:

  • 创建一个自定义结构(如:合并值到一个特殊格式的字符串、构造非标准 Map 等)
  • 控制并行流合并逻辑(比如收集到线程安全容器)
  • 优化性能(跳过不必要的转换)

那么实现 Collector 接口就是最灵活且强大的方式。


☕ 自定义 Collector 的三种方式

方法 描述 适用场景
✅ 使用 Collectors 工厂方法 组合已有收集器,或配合 collectingAndThen() 做轻度自定义 推荐优先使用
✅ 使用 Stream.collect(supplier, accumulator, combiner) 自行传入构造、累加与合并逻辑 中等灵活性
✅❗ 实现 Collector<T, A, R> 接口 完全掌控所有阶段,适合高度定制 最灵活,但技术门槛高

📐 理解 Collector<T, A, R> 的三个类型参数

我们先看一下接口定义:

java 复制代码
interface Collector<T, A, R> {
    ...
}
  • T:流中元素的类型
  • A:中间可变容器类型(Accumulator 类型)
  • R:最终返回结果类型(Result 类型)

🚗 举例说明

收集器 T(流中元素) A(中间容器) R(最终结果)
toList() String ArrayList<String> List<String>
toSet() String HashSet<String> Set<String>
groupingBy(String::length, counting()) String 内部 Map + Counter Map<Integer, Long>

➡️ 注意:我们平时用 Collectors.toList() 等时,看不到 A 的具体类型,是因为返回类型中对它进行了隐藏(用 ? 代替了)。


📋 代码示例:查看 Collector 类型参数

java 复制代码
Collection<String> strings = List.of(
    "two", "three", "four", "five", "six", "seven", "eight", "nine",
    "ten", "eleven", "twelve"
);

// toList
Collector<String, ?, List<String>> listCollector = Collectors.toList();
List<String> list = strings.stream().collect(listCollector);
System.out.println("Size of list = " + list.size()); // 11

// toSet
Collector<String, ?, Set<String>> setCollector = Collectors.toSet();
Set<String> set = strings.stream().collect(setCollector);
System.out.println("Size of set = " + set.size()); // 11

// groupingBy + counting
Collector<String, ?, Map<Integer, Long>> groupingCollector =
    Collectors.groupingBy(String::length, Collectors.counting());
Map<Integer, Long> map = strings.stream().collect(groupingCollector);
System.out.println("Size of map = " + map.size()); // 4

这些例子中,? 代表我们无需关心中间类型 A------由 API 实现者决定,我们只关心结果类型 R。


🧪 补充示例:自定义 Collector 实现(首字母统计)

我们实现一个 collector,用于按单词首字母统计出现次数:

java 复制代码
class FirstLetterCountCollector implements Collector<String, Map<Character, Integer>, Map<Character, Integer>> {

    @Override
    public Supplier<Map<Character, Integer>> supplier() {
        return HashMap::new;
    }

    @Override
    public BiConsumer<Map<Character, Integer>, String> accumulator() {
        return (map, word) -> {
            char first = word.charAt(0);
            map.merge(first, 1, Integer::sum);
        };
    }

    @Override
    public BinaryOperator<Map<Character, Integer>> combiner() {
        return (map1, map2) -> {
            map2.forEach((k, v) -> map1.merge(k, v, Integer::sum));
            return map1;
        };
    }

    @Override
    public Function<Map<Character, Integer>, Map<Character, Integer>> finisher() {
        return Function.identity(); // 直接返回中间容器
    }

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

使用:

java 复制代码
List<String> words = List.of("apple", "apricot", "banana", "blueberry", "cherry");

Map<Character, Integer> counts = words.stream()
    .collect(new FirstLetterCountCollector());

System.out.println(counts); // {a=2, b=2, c=1}

🧠 总结:自定义 Collector 的 5 个核心方法

方法 作用
supplier() 创建中间结果容器
accumulator() 累加流中的每个元素
combiner() 并行流中合并两个中间结果
finisher() 将中间容器转换为最终结果
characteristics() 提供 collector 的特性,如是否为并发、安全等

✅ Collector 特性(characteristics())常见值

特性 说明
CONCURRENT 支持并发(accumulator 线程安全)
UNORDERED 不依赖顺序(如 Set 类型)
IDENTITY_FINISH AR 类型相同,finisher() 可直接返回
相关推荐
狂奔小菜鸡22 分钟前
Day41 | Java中的锁分类
java·后端·java ee
hooknum35 分钟前
学习记录:基于JWT简单实现登录认证功能-demo
java
悟空爬虫1 小时前
UV实战教程,我啥要从Anaconda切换到uv来管理包?
python
程序员Terry1 小时前
同事被深拷贝坑了3小时,我教他原型模式的正确打开方式
java·设计模式
NE_STOP1 小时前
MyBatis-缓存与注解式开发
java
dev派1 小时前
AI Agent 系统中的常用 Workflow 模式(1)
python·langchain
码路飞1 小时前
不装 OpenClaw,我用 30 行 Python 搞了个 QQ AI 机器人
java
Re_zero2 小时前
以为用了 try-with-resources 就稳了?这三个底层漏洞让TCP双向通讯直接卡死
java·后端
SimonKing2 小时前
Fiddler抓包完全指南:从安装配置到抓包,一文讲透
java·后端·程序员
明月_清风3 小时前
从“能用”到“专业”:构建生产级装饰器与三层逻辑拆解
后端·python