Java Stream API 与集合 API 是分工协作关系:集合负责存储数据,Stream 负责计算处理;前者可反复读写、长期驻留,后者为一次性的无状态计算管道,强调声明式、内部迭代与链式操作。

Java Stream API 和集合 API 不是“谁取代谁”的关系,而是分工明确、协同工作的搭档。集合负责存数据,Stream 负责算数据——一个管“家”,一个管“事”。面试中常被问到二者区别,关键不是背概念,而是讲清角色、行为和适用边界。
核心定位不同:存储 vs 计算
集合(List、Set、Map)是数据容器,强调“持有”:可反复读、可增删改、长期驻留内存;Stream 是计算管道,强调“处理”:不保存数据、不可复用、一次消费即关闭。调用 list.stream() 就像打开水龙头——水(数据)来自水管(集合),但水流(Stream)本身不存水,关掉就没了。
编程风格差异:命令式循环 vs 声明式流水线
传统集合操作靠 for 循环 + 临时变量 + if 判断,逻辑分散、易出错;Stream 把意图直接写出来:
- “我要薪资大于1万的员工姓名” → list.stream().filter(e -> e.getSalary() > 10000).map(Employee::getName).collect(toList())
- “我要前5个非空字符串转大写” → list.stream().filter(Objects::nonNull).limit(5).map(String::toUpperCase).collect(toList())
你描述目标,JVM 负责执行路径优化(比如 limit + filter 可能短路,sorted + limit 可能只排部分)。
立即学习“Java免费学习笔记(深入)”;
执行机制对比:外部迭代 vs 内部迭代
集合遍历由开发者控制节奏(外部迭代),容易写错边界、漏状态;Stream 由框架在底层统一拉取、分发、聚合(内部迭代):
- forEach()、findAny() 等终端操作触发后,整个流水线才真正运行
- 中间操作(filter/map/sorted)只是登记动作,不执行也不生成中间集合
- 并行切换只需把 stream() 换成 parallelStream(),无需手写线程池或合并逻辑
实际使用注意点
Stream 好用,但不能滥用:
- 小数据量、简单逻辑(如单次遍历取值)用传统循环更直观,不必强套 Stream
- 需要多次复用相同数据时,别反复调用同一个 Stream 实例(会抛 IllegalStateException),应封装为 Supplier<Stream>
- 对比两个 List 差异时,避免 listA.stream().filter(e -> !listB.contains(e)) 这种 O(n²) 写法;优先转 listB 为 HashSet,再 filter,降到 O(n)
- Stream 结果要落回集合,必须用 collect();它不改变原集合,所有操作都是无副作用的


















