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() 可直接返回
相关推荐
兵慌码乱5 小时前
面向桌面端的资产管理系统分层架构设计与核心模块实现
python·系统架构·sqlite·pyqt5·数据库设计·桌面应用开发·mvc架构
咖啡八杯6 小时前
GoF设计模式——策略模式
java·后端·spring·设计模式
hboot7 小时前
AI工程师第三课 - 机器学习基础
python·scikit-learn·kaggle
顾林海12 小时前
Agent入门阶段-编程基础-Python:流程控制
python·agent·ai编程
用户1285261160214 小时前
我把祖传Java项目重构后,接口响应从3s砍到了200ms,只改了这几行代码
java
Linsk14 小时前
组件 = 模板 + 业务逻辑
java·前端·vue.js
呱呱复呱呱14 小时前
Django CBV 源码解读:一个请求是怎么找到你的 get() 方法的
python·django
星沉远浦15 小时前
用Gemini高效解决Java代码报错难以定位的问题
java
用户2986985301419 小时前
Word 文档字符级格式化:Java 实现方案详解
java·后端
曲幽19 小时前
刚部署的 LibreTranslate 频频翻车?我掏出了 20 年前的 StarDict 词典,用 FastAPI 搭了个本地词典翻译 API
python·fastapi·web·translate·goldendict·libretranslate·stardict·pystardict