当前位置: 首页 > news >正文

Java 流式编程(Stream)完整详解

目录

一、基础概念

1. 流的三要素

2. 流的特点

二、创建 Stream(数据源)

1. 从集合创建(最常用)

2. 从数组创建

3. 直接创建空流 / 指定元素流

4. 无限流(生成 / 迭代)

三、中间操作(Intermediate)

1. 常用无状态操作(不依赖前后元素)

filter 过滤

map 映射(类型转换 / 字段提取)

flatMap 扁平化映射(拆分层级)

peek 查看 / 调试流

2. 常用有状态操作(依赖全部元素 / 顺序)

distinct 去重

sorted 排序

limit /skip 截取 / 跳过

四、终端操作(Terminal)

1. forEach /forEachOrdered 遍历

2. collect 收集(最核心)

① 转为 List / Set / 数组

② 拼接字符串 joining

③ 分组 groupingBy(类似 SQL group by)

④ 分区 partitioningBy(二分区:true/false)

⑤ 聚合统计(count、max、min、avg、sum)

3. 匹配操作(返回 boolean)

4. 查找操作

5. 规约 reduce(聚合计算,自定义累加)

五、数值流(IntStream / LongStream / DoubleStream)

1. 转换数值流

2. 范围创建数值流

3. 数值便捷计算

六、并行流 parallelStream

1. 开启方式

2. 原理

3. 注意事项(坑)

七、完整实战示例(传统循环 VS 流式)

传统 for 循环

Stream 流式写法(一行链式)

八、常见避坑总结

九、Java 9+ 新增增强(拓展)


Java 8 引入Stream 流,用于集合 / 数组的链式、函数式数据处理,替代传统循环遍历,代码更简洁、可读性强,支持并行计算。

核心定位:不是数据结构,是数据的「处理管道」,不存储数据,只操作数据源。


一、基础概念

1. 流的三要素

  1. 数据源:集合、数组、IO 流、生成器等
  2. 中间操作:链式调用,延迟执行(返回新 Stream),可多次叠加
  3. 终端操作:触发整个流执行,关闭流(流只能用一次)

2. 流的特点

  • 惰性求值:中间操作直到终端调用才执行
  • 单向不可逆:流一旦终端消费,不能重复使用
  • 不修改原数据源:所有操作返回新结果,原集合不变
  • 支持并行流:简单切换即可利用多线程

二、创建 Stream(数据源)

1. 从集合创建(最常用)

List<String> list = Arrays.asList("A", "B", "C"); // 顺序流 Stream<String> stream = list.stream(); // 并行流 Stream<String> parallelStream = list.parallelStream();

2. 从数组创建

String[] arr = {"1", "2", "3"}; Stream<String> stream = Arrays.stream(arr);

3. 直接创建空流 / 指定元素流

// 空流 Stream<String> empty = Stream.empty(); // 可变参数创建流 Stream<Integer> numStream = Stream.of(1, 2, 3, 4);

4. 无限流(生成 / 迭代)

常用于造测试数据,必须配合 limit 截断,否则死循环

// 迭代:从0开始,每次+2 Stream.iterate(0, n -> n + 2).limit(5).forEach(System.out::println); // 生成:随机数 Stream.generate(Math::random).limit(3).forEach(System.out::println);

三、中间操作(Intermediate)

返回 Stream,可链式拼接,延迟执行,分为:无状态、有状态。

1. 常用无状态操作(不依赖前后元素)

filter 过滤

筛选符合条件元素,参数Predicate断言

List<Integer> nums = Arrays.asList(1,2,3,4,5,6); nums.stream() .filter(n -> n > 3) // 保留大于3的数 .forEach(System.out::println);
map 映射(类型转换 / 字段提取)

一对一转换,参数Function

// 数字转字符串 nums.stream().map(String::valueOf).forEach(System.out::println); // 实体类提取字段(示例) class User { String name; } List<User> userList = new ArrayList<>(); userList.stream().map(User::getName).forEach(System.out::println);
flatMap 扁平化映射(拆分层级)

一对多,把流中的集合 / 数组拆解为单个元素,解决嵌套集合

List<List<String>> nested = Arrays.asList( Arrays.asList("a","b"), Arrays.asList("c","d") ); // 扁平化:两层集合 → 单层流 nested.stream() .flatMap(Collection::stream) .forEach(System.out::println);
peek 查看 / 调试流

遍历元素,不改变流,多用于打印日志、调试

nums.stream() .peek(n -> System.out.println("原始:" + n)) .filter(n -> n % 2 == 0) .peek(n -> System.out.println("过滤后:" + n)) .count(); // 终端触发执行

2. 常用有状态操作(依赖全部元素 / 顺序)

distinct 去重

基于equals()+hashCode()去重

Arrays.asList(1,2,2,3,3,3).stream() .distinct() .forEach(System.out::println);
sorted 排序
  • 无参:自然排序(实现 Comparable)
  • 有参:自定义 Comparator 比较器
// 自然升序 nums.stream().sorted().forEach(System.out::println); // 自定义降序 nums.stream().sorted(Comparator.reverseOrder()).forEach(System.out::println);
limit /skip 截取 / 跳过
  • limit(n):取前 n 个元素
  • skip(n):跳过前 n 个元素
// 跳过前2个,取后3个 nums.stream().skip(2).limit(3).forEach(System.out::println);

四、终端操作(Terminal)

触发流执行,流关闭,不能继续链式调用,分为:遍历、收集、匹配、聚合、规约等。

1. forEach /forEachOrdered 遍历

  • forEach:顺序流有序,并行流无序
  • forEachOrdered:并行流也保证遍历顺序
nums.stream().forEach(System.out::println); nums.parallelStream().forEachOrdered(System.out::println);

2. collect 收集(最核心

将流转回 集合、字符串、分组、分区等,Collectors工具类提供大量静态方法。

① 转为 List / Set / 数组
// 转 List List<Integer> list = nums.stream().collect(Collectors.toList()); // 转 Set(自动去重) Set<Integer> set = nums.stream().collect(Collectors.toSet()); // 转数组 Integer[] array = nums.stream().toArray(Integer[]::new);
② 拼接字符串 joining
List<String> strs = Arrays.asList("Java","Stream","Demo"); // 直接拼接 String s1 = strs.stream().collect(Collectors.joining()); // 分隔符拼接 String s2 = strs.stream().collect(Collectors.joining(",")); // 分隔符 + 前缀 + 后缀 String s3 = strs.stream().collect(Collectors.joining(",", "[", "]"));
③ 分组 groupingBy(类似 SQL group by)
List<User> userList = Arrays.asList( new User("张三", 20), new User("李四", 22), new User("王五", 20) ); // 按年龄分组 key:年龄 value:同年龄用户集合 Map<Integer, List<User>> group = userList.stream() .collect(Collectors.groupingBy(User::getAge));
④ 分区 partitioningBy(二分区:true/false)

只能分成两组,返回Map<Boolean, List<T>>

// 分区:年龄>=20 / <20 Map<Boolean, List<User>> part = userList.stream() .collect(Collectors.partitioningBy(u -> u.getAge() >= 20));
⑤ 聚合统计(count、max、min、avg、sum)
// 一次性统计:数量、总和、最大、最小、平均值 IntSummaryStatistics stat = nums.stream() .collect(Collectors.summarizingInt(Integer::intValue)); stat.getCount(); stat.getSum(); stat.getMax();

3. 匹配操作(返回 boolean)

// allMatch:全部满足 boolean all = nums.stream().allMatch(n -> n > 0); // anyMatch:任意一个满足 boolean any = nums.stream().anyMatch(n -> n == 3); // noneMatch:全部不满足 boolean none = nums.stream().noneMatch(n -> n < 0);

4. 查找操作

// findFirst:获取第一个元素(顺序流稳定) Optional<Integer> first = nums.stream().findFirst(); // findAny:获取任意元素(并行流效率更高) Optional<Integer> anyEle = nums.parallelStream().findAny();

注意:返回Optional,防止空指针。

5. 规约 reduce(聚合计算,自定义累加)

把流中元素反复结合得到一个值,常用于求和、求积、拼接。

List<Integer> numList = Arrays.asList(1,2,3,4); // 1. 无初始值:返回 Optional Optional<Integer> sum1 = numList.stream().reduce(Integer::sum); // 2. 有初始值:直接返回结果(不会空) Integer sum2 = numList.stream().reduce(0, Integer::sum); // 自定义累加逻辑 Integer total = numList.stream().reduce(0, (a, b) -> a + b * 2);

五、数值流(IntStream / LongStream / DoubleStream)

普通Stream<Integer>存在自动装箱 / 拆箱损耗,Java 提供专用数值流提升性能。

1. 转换数值流

List<Integer> list = Arrays.asList(1,2,3); // 转 IntStream IntStream intStream = list.stream().mapToInt(Integer::intValue); // 转回包装流 Stream<Integer> stream = intStream.boxed();

2. 范围创建数值流

// [1,5] 闭区间 IntStream.rangeClosed(1,5).forEach(System.out::println); // [1,5) 左闭右开 IntStream.range(1,5).forEach(System.out::println);

3. 数值便捷计算

int sum = intStream.sum(); int max = intStream.max().getAsInt(); double avg = intStream.average().getAsDouble();

六、并行流 parallelStream

1. 开启方式

// 方式1:集合直接调用 list.parallelStream(); // 方式2:顺序流转并行 list.stream().parallel();

2. 原理

底层基于Fork/Join 框架,多线程拆分任务并行执行,大数据集提升明显。

3. 注意事项(坑)

  1. 非线程安全集合不要用并行流,会并发修改异常
  2. 依赖顺序的逻辑慎用并行流(findAnyforEach会乱序)
  3. 小数据量:并行流有线程开销,反而更慢
  4. 不要在并行流中操作外部可变变量

七、完整实战示例(传统循环 VS 流式)

需求:过滤偶数 → 平方 → 去重 → 收集为 List

传统 for 循环

List<Integer> source = Arrays.asList(1,2,2,3,4,4,5); List<Integer> result = new ArrayList<>(); for (Integer n : source) { if (n % 2 == 0) { int square = n * n; if (!result.contains(square)) { result.add(square); } } }

Stream 流式写法(一行链式)

List<Integer> result = source.stream() .filter(n -> n % 2 == 0) .map(n -> n * n) .distinct() .collect(Collectors.toList());

八、常见避坑总结

  1. 流只能使用一次:终端操作后流关闭,重复调用抛IllegalStateException
  2. 中间操作延迟执行:没有终端操作,中间代码完全不运行
  3. 避免在流中修改原集合 / 外部变量
  4. 实体类去重、比较务必重写equals()hashCode()
  5. 基础类型优先用数值流,减少装箱拆箱
  6. 并行流只适合无状态、不依赖顺序、大数据量场景

九、Java 9+ 新增增强(拓展)

  1. Stream.ofNullable():支持单个 null 元素创建流
  2. takeWhile() / dropWhile():按条件截断流
  3. 集合新增stream()重载,优化空集合场景
http://www.gsyq.cn/news/1521508.html

相关文章:

  • 从DDR3到DDR4,你的老电脑升级内存划算吗?实测性能提升与兼容性全解析
  • Triton模型服务化与持续可观测性实战指南
  • 在Visual Studio 2022里,用C#和OpenTK 4.x画个会转的彩色立方体(附完整代码)
  • 别再踩坑了!STM32F103C8T6的PB3/PB4/PA15引脚当普通IO口用的完整配置流程(附MDK设置截图)
  • Java中String内部排序方法
  • 别再傻傻分不清了!用大白话和一张图讲透图形渲染里的AABB、KD树和BVH
  • 千脑理论仿真:用皮层柱建模感觉-位置绑定与分布式共识
  • 告别漫长等待!手把手教你用Ansys Speos 2022R2的GPU加速,把光学仿真速度提上来
  • 从MBTI到SCL-90:拆解互联网公司校招测评背后的逻辑,技术/非技术岗如何‘对号入座’
  • STM32新手避坑:为什么我建议你先学标准库,再碰HAL库?
  • 避坑指南:城市热岛研究中,用MODIS和Landsat算地表温度,结果差多少?实测对比来了
  • 保姆级教程:用Cadence 17.2为ESP8266-12F和OpenMV设计无人机供电与WIFI电路
  • 告别黑屏!手把手教你安装配置易至天工ArcGIS影像插件(支持10.2-10.8)
  • 从AMD EPYC到3D V-Cache:手把手拆解Chiplet实战中的封装技术选型(2.5D/3D全解析)
  • Ubuntu 20.04上,放弃Sealos!我用KubeKey 2.0.0快速搞定K8s集群,再部署DeepFlow社区版
  • WSL2下CUDA多版本共存与切换:一个命令搞定PyTorch/TensorFlow环境切换
  • 蓝桥杯EDA省赛真题复盘:从电源设计到PCB走线,这10个硬件知识点你掌握了吗?
  • 密钥派生函数选型避坑:从NIST SP800-108更新看HMAC、CMAC、KMAC怎么选
  • 深入对比:PCA9306、TXS0108E、BSS138,你的I2C电平转换方案选对了吗?
  • 如何高效配置Realtek RTW89 WiFi 7网卡驱动:专业开发者的完整指南
  • DeepSeek安全对齐与合规应用实践指南
  • 别再死记硬背了!用VisionMaster的N点标定,手把手教你搞定相机与机械臂的‘语言翻译’
  • RVC vs SVC实战对比:AI变声炼丹,哪个更适合你的显卡和需求?(附避坑指南)
  • 别再只盯着RSA了:聊聊车联网安全中ECC密钥如何省下宝贵的芯片资源
  • ATGM332D-5N vs U-blox NEO:多模GPS模块选型与避坑指南
  • 2026年辽阳合金钢管源头厂家有哪些,20# 精密钢管/方管/无缝方矩管/合金钢管,合金钢管供应厂家哪家权威 - 品牌推荐师
  • 博弈论实战指南:从收益矩阵到现实决策的五步法
  • Java计算机毕设之基于 SpringBoot 的人格类型分析与测评系统设计 大众在线人格心理测试平台的设计与实现(完整前后端代码+说明文档+LW,调试定制等)
  • 2026年隧道风机选购指南:从技术参数到工程案例的深度分析 - 优质品牌商家
  • 告别外围电路烦恼:用川土微CS485xx芯片简化你的工业485电路设计