321. Java Stream API - 使用 StringBuffer 收集原始类型流
在 Java 的 Stream API 中,我们常常使用 Collectors.joining() 方法将对象流中的元素拼接成字符串,例如:
Stream.of("A", "B", "C").collect(Collectors.joining()); // 结果是 "ABC"
但这个方法只适用于对象流(如 Stream),无法直接用于 IntStream、LongStream 或 DoubleStream 等原始类型流。
❓那如果我们想拼接一个 IntStream 怎么办?
由于 String 是不可变类,每次拼接字符串都会创建新的对象,性能低下。Java 推荐使用可变的字符串容器 —— StringBuffer 或 StringBuilder。
这里我们将使用 StringBuffer 来拼接 IntStream 中的元素。
🔨 实现方式:手动构建 Collector
就像之前讲的,我们可以使用三个组件手动构建一个 collector,用于将 IntStream 拼接成一个字符串:
🧩 三个组件
Supplier<StringBuffer> supplier = StringBuffer::new;
ObjIntConsumer<StringBuffer> accumulator = StringBuffer::append;
BiConsumer<StringBuffer, StringBuffer> combiner = StringBuffer::append;
supplier:提供一个新的StringBuffer对象accumulator:将每个 int 元素追加到StringBuffer中combiner:并行流处理时合并多个StringBuffer
✅ 示例代码
import java.util.function.*;
import java.util.stream.*;
public class PrimitiveJoinExample {
public static void main(String[] args) {
Supplier<StringBuffer> supplier = StringBuffer::new;
ObjIntConsumer<StringBuffer> accumulator = StringBuffer::append;
BiConsumer<StringBuffer, StringBuffer> combiner = StringBuffer::append;
StringBuffer result = IntStream.range(0, 10)
.collect(supplier, accumulator, combiner);
System.out.println("collect = " + result);
}
}
📦 输出结果:
collect = 0123456789
流中的每个整数依次被拼接成字符串,就像我们用 Collectors.joining() 处理字符串一样。
💬 延伸讲解
- 为什么不能用 String?
因为
String是不可变的,每次拼接都会生成一个新对象,效率低; - 为什么用
StringBuffer而不是StringBuilder?StringBuffer是线程安全的,在并行流中更可靠。但如果你确定是串行流,可以使用StringBuilder提升性能。
🧪 试试看并行流!
StringBuffer result = IntStream.range(0, 10)
.parallel()
.collect(supplier, accumulator, combiner);
System.out.println(result);
因为使用了线程安全的 StringBuffer,即使是并行流也能正确工作。
🎯 小结
| 目标 | 实现方式 |
|---|---|
将 IntStream 拼接成字符串 | 使用 StringBuffer 和 collect(supplier, accumulator, combiner) |
替代 Collectors.joining() 但适用于原始类型 | ✅ |