应优先使用原始类型特化流(如IntStream)、慎用parallelStream()、保持操作无状态、善用懒惰求值与短路操作。例如用IntStream.rangeClosed替代List<Integer>流,避免装箱拆箱;并行仅适用于大数据量且计算密集场景;filter后接limit可提前终止;用min()替代sorted().findFirst()更高效。

直接用 Lambda 和 Stream 写代码很顺手,但几个关键点没注意,性能可能反而变差。重点不在“能不能写”,而在“怎么写才不拖慢程序”。
避免频繁装箱和拆箱
Stream 默认处理的是引用类型,比如 Stream<Integer>,对大量整数做计算时,每次操作都会触发自动装箱/拆箱,开销明显。
- 改用原始类型特化流:如 IntStream、LongStream、DoubleStream
- 不要写
list.stream().mapToInt(x -> x)后又转回对象流;尽量从源头就用原始数组或 IntStream.range() - 例如统计 1 到 100 万的平方和,用
IntStream.rangeClosed(1, 1_000_000).mapToLong(i -> (long) i * i).sum()比用List<Integer>+stream().map(...)快数倍
慎用 parallelStream(),别默认“并行=更快”
并行流依赖 Fork/Join 框架拆分任务,但拆分本身有成本,小数据或结构不适合拆分时,反而更慢。
- 适合并行:数据量大(通常 > 10,000 元素)、计算密集、源集合支持高效分割(如 ArrayList、数组)
- 不适合并行:数据量小、LinkedList 或自定义集合(拆分代价高)、含 IO 操作(如文件读取、网络请求)、中间操作含装箱/同步逻辑
- 简单判断方法:用
System.nanoTime()对比stream()和parallelStream()的执行时间,别凭感觉
保持无状态、避免共享可变变量
Stream 管道中若使用外部变量修改状态(比如在 forEach 里往 ArrayList 添加元素),不仅线程不安全,并行时还会出错或结果错乱。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
立即学习“Java免费学习笔记(深入)”;
- 所有中间操作(
filter、map、sorted)应是无状态的:输出只取决于当前输入,不依赖外部变量 - 终端操作如需收集结果,优先用
collect(Collectors.toList())这类线程安全的收集器,而不是自己 new ArrayList 再 add - 如果真要调试或记录中间值,用
peek(),但它不改变流行为,也别在里面做耗时或副作用操作
别忽略懒惰求值和短路操作的价值
Stream 的中间操作不会立即执行,只有遇到终端操作才真正触发。合理利用这点能省掉大量无效计算。
- 用
findAny()或anyMatch()替代filter().collect()查是否存在满足条件的元素 - 大数据过滤后只取前 N 条,用
limit(N)放在filter后面,能提前终止后续处理 - 避免写
stream().sorted().findFirst()处理大集合——排序是 O(n log n),而min(Comparator)是 O(n)
这些不是硬性限制,而是基于 JVM 实现机制和常见数据规模的经验总结。写完一段 Stream 逻辑,花半分钟想想它实际做了什么、数据有多大、有没有更直接的路径,往往比调优参数更有效。


















