文章目录
- [327. Java Stream API - 实现 `joining()` 收集器:从简单到进阶](#327. Java Stream API - 实现
joining()收集器:从简单到进阶) -
- [🧱 基础版 `Joining` 收集器实现](#🧱 基础版
Joining收集器实现) - [📦 示例使用](#📦 示例使用)
-
- [✅ 输出结果:](#✅ 输出结果:)
- [🎯 关键点讲解](#🎯 关键点讲解)
- [💡 思考:为什么没有使用 `IDENTITY_FINISH`?](#💡 思考:为什么没有使用
IDENTITY_FINISH?) - [🌟 进阶版:带分隔符、前缀和后缀](#🌟 进阶版:带分隔符、前缀和后缀)
- [🚀 带参数的 Joining 实现示例](#🚀 带参数的 Joining 实现示例)
- [✅ 使用方式](#✅ 使用方式)
- [🧠 总结](#🧠 总结)
- [🧱 基础版 `Joining` 收集器实现](#🧱 基础版
327. Java Stream API - 实现 joining() 收集器:从简单到进阶
在 Java Stream API 中,Collectors.joining() 是一个专门用于字符串拼接的收集器。它将多个字符串元素连接成一个单一字符串。今天我们将手动实现这个收集器,并理解其背后的实现机制。
🧱 基础版 Joining 收集器实现
我们首先实现一个最基础的 joining() 收集器版本,不带任何分隔符、前缀或后缀。
java
class Joining implements Collector<String, StringBuffer, String> {
@Override
public Supplier<StringBuffer> supplier() {
return StringBuffer::new; // 用于累加字符串的可变容器
}
@Override
public BiConsumer<StringBuffer, String> accumulator() {
return StringBuffer::append; // 将每个字符串追加到容器中
}
@Override
public BinaryOperator<StringBuffer> combiner() {
return StringBuffer::append; // 合并两个 StringBuffer(用于并行流)
}
@Override
public Function<StringBuffer, String> finisher() {
return Object::toString; // 将 StringBuffer 转换成最终的字符串
}
@Override
public Set<Characteristics> characteristics() {
return Set.of(); // 没有特性:不是 UNORDERED,也不是 IDENTITY_FINISH,也不支持并发
}
}
📦 示例使用
java
Collection<String> strings = List.of("one", "two", "three", "four", "five");
String result = strings.stream()
.collect(new Joining());
System.out.println("result = " + result);
✅ 输出结果:
java
result = onetwothreefourfive
🎯 关键点讲解
| 方法 | 作用 |
|---|---|
supplier() |
提供一个 StringBuffer 实例,作为中间结果的容器 |
accumulator() |
将流中的每个字符串添加到容器中 |
combiner() |
合并两个部分结果(并行流场景) |
finisher() |
把 StringBuffer 转换为最终结果 String |
characteristics() |
返回空集合,表示没有特性 |
💡 思考:为什么没有使用 IDENTITY_FINISH?
因为 StringBuffer 和最终返回的类型 String 是不同的类型,所以不能声明为 IDENTITY_FINISH。一旦 finisher() 不是"返回原值",就必须省略该特性。
🌟 进阶版:带分隔符、前缀和后缀
你可能想实现这样的拼接:
java
String result = strings.stream()
.collect(Collectors.joining(", ", "[", "]"));
// 输出: [one, two, three, four, five]
这时候我们就需要使用 StringJoiner 作为中间容器了,因为它原生支持 delimiter(分隔符) 、prefix(前缀) 和 suffix(后缀)。
🚀 带参数的 Joining 实现示例
java
class JoiningWithDelimiter implements Collector<String, StringJoiner, String> {
private final String delimiter;
private final String prefix;
private final String suffix;
public JoiningWithDelimiter(String delimiter, String prefix, String suffix) {
this.delimiter = delimiter;
this.prefix = prefix;
this.suffix = suffix;
}
@Override
public Supplier<StringJoiner> supplier() {
return () -> new StringJoiner(delimiter, prefix, suffix);
}
@Override
public BiConsumer<StringJoiner, String> accumulator() {
return StringJoiner::add;
}
@Override
public BinaryOperator<StringJoiner> combiner() {
return StringJoiner::merge;
}
@Override
public Function<StringJoiner, String> finisher() {
return StringJoiner::toString;
}
@Override
public Set<Characteristics> characteristics() {
return Set.of(); // 同样不能是 IDENTITY_FINISH
}
}
✅ 使用方式
java
String result = strings.stream()
.collect(new JoiningWithDelimiter(", ", "[", "]"));
System.out.println("result = " + result);
输出结果:
java
result = [one, two, three, four, five]
🧠 总结
| 特性 | 基础版 | 进阶版 |
|---|---|---|
| 容器类型 | StringBuffer |
StringJoiner |
| 是否支持分隔符/前缀/后缀 | 否 | ✅ 支持 |
finisher 是 identity 吗? |
否 | 否 |
| 特性集(characteristics) | 空 | 空 |