文章目录
- 279. Java Stream API - Stream 拼接的两种方式:`concat()` vs `flatMap()`
- 🎯 本节目标
- 🧪 背景问题:多个集合如何组合成一个流?
- ✅ 方式一:使用 `Stream.concat()`
- 📌 特点:
- 🔨 示例代码:
- 🔽 输出:
- ❌ 局限:只能拼接两个流!
- ✅ 方式二:使用 `flatMap()` 动态拼接多个流
- 📌 特点:
- 🔨 示例代码:
- 🔽 输出:
- 🧠 为什么 `concat()` 不用可变参数(`varargs`)?
- 🔍 性能对比与底层机制
- 🚦 关于 SIZED 特性小贴士:
- 🔚 总结选择建议
- 🔁 拓展练习题
- ☑️ 合并三个列表并打印奇数元素
279. Java Stream API - Stream 拼接的两种方式:concat()vsflatMap()
🎯 本节目标
- 理解
Stream.concat()和flatMap()实现流拼接的方式 - 掌握两种方法的使用场景、性能差异与行为特性
- 明确什么时候使用哪种方式更合适
🧪 背景问题:多个集合如何组合成一个流?
假设我们有多个List<Integer>,我们想要将它们的元素拼接成一个大集合。
✅ 方式一:使用Stream.concat()
📌 特点:
- 适用于拼接两个流
- 顺序是:先处理第一个流,再处理第二个流
- 返回的流具有
SIZED属性(已知大小)
🔨 示例代码:
List<Integer>list0=List.of(1,2,3);List<Integer>list1=List.of(4,5,6);List<Integer>concat=Stream.concat(list0.stream(),list1.stream()).toList();System.out.println("concat = "+concat);🔽 输出:
concat=[1,2,3,4,5,6]🧠 类比:就像把两个数组首尾缝在一起,中间没有拆分、合并的额外动作。
❌ 局限:只能拼接两个流!
如果你有 3 个、4 个、N 个流,就得嵌套调用:
Stream<Integer>result=Stream.concat(Stream.concat(list0.stream(),list1.stream()),list2.stream());📉 问题:每concat一次,就会生成一个临时中间流,内存和效率都有开销!
✅ 方式二:使用flatMap()动态拼接多个流
📌 特点:
- 支持多个流拼接(不限数量)
- 性能更优:只创建一个外层流
- 缺点是:返回的流没有 SIZED 属性(大小未知)
🔨 示例代码:
List<Integer>list0=List.of(1,2,3);List<Integer>list1=List.of(4,5,6);List<Integer>list2=List.of(7,8,9);List<Integer>flatMap=Stream.of(list0.stream(),list1.stream(),list2.stream()).flatMap(Function.identity())// 展平流.toList();System.out.println("flatMap = "+flatMap);🔽 输出:
flatMap=[1,2,3,4,5,6,7,8,9]🧠 类比:像是一个“展开三明治”——先把所有流打包,再逐个展开并合并元素。
🧠 为什么concat()不用可变参数(varargs)?
你可能好奇:为什么concat()不能接收多个流,比如这样:
Stream.concat(stream1,stream2,stream3);// ❌ 不支持📌 原因是:
- 每次
concat()只能拼接两个流 - 若要拼接多个,建议使用
flatMap()来减少中间流的创建
🔍 性能对比与底层机制
| 特性 | concat() | flatMap() |
|---|---|---|
| 支持多个流拼接 | 否(只能两个) | ✅ 支持任意多个流 |
| 是否创建中间临时流 | 是(每两个拼接都创建) | 否(只创建一个外层流) |
| 返回流是否有大小信息 | ✅ 是(SIZED) | ❌ 否(不再是 SIZED) |
| 内部优化可能性 | 更易优化 | 较难优化 |
🚦 关于 SIZED 特性小贴士:
- 如果你使用
Stream.concat(),结果流的大小是可预知的 →Stream会自动标记为SIZED - 如果使用
flatMap(),因为展开过程中元素数不确定,所以结果流被标记为UNKNOWN
🔧 有些操作(如并行流优化、预分配内存)依赖SIZED特性,因此concat在某些场景下有优势。
🔚 总结选择建议
| 场景 | 建议使用 |
|---|---|
| 只拼接两个流 | ✅concat() |
| 拼接多个流 | ✅flatMap() |
| 希望保留流大小信息(如并行优化) | ✅concat() |
| 性能优先、避免中间流创建 | ✅flatMap() |
🔁 拓展练习题
☑️ 合并三个列表并打印奇数元素
List<Integer>combined=Stream.of(list0.stream(),list1.stream(),list2.stream()).flatMap(Function.identity()).filter(n->n%2!=0).toList();System.out.println("odd numbers = "+combined);