当前位置: 首页 > 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.jsqmd.com/news/1009700/

相关文章:

  • 汽车MCU里的‘内存保镖’:手把手配置瑞萨芯片的ECC纠错功能(附寄存器详解)
  • 三步搞定显卡噪音:FanControl零基础调校指南
  • 多旋翼控制分配(Control Allocation)原理与实战指南
  • GPT-4参数规模与MoE稀疏激活的工程真相
  • FastAPI 2026性能本质:协议适配、类型即运行时、依赖即调度
  • 想发SCI四区交通类论文?聊聊这本开源期刊JAT的投稿避坑指南与APC费用详解
  • 从DDR3到DDR4,你的老电脑升级内存划算吗?实测性能提升与兼容性全解析
  • 给你的STM32项目加个“眼睛”:1.8寸ST7735屏的GUI界面快速上手教程
  • 物理AI落地实战:VLA模型的Agentic Skills增强方案
  • STM32F407内存不够用?手把手教你用.sct文件把FreeRTOS塞进CCM(64K专属RAM)
  • 2026长沙二手房整体翻新技术测评:长沙旧房改造价格/长沙旧房改造公司/长沙旧房改造工期/三家实力厂商工艺拆解 - 优质品牌商家
  • SketchUp STL插件终极指南:3D打印工作流的革命性突破
  • GPT-4参数量与MoE激活机制的工程真相
  • K210的KPU到底有多强?实测YOLO v2物体检测的帧率与功耗,对比树莓派Zero 2 W
  • Triton模型服务化与持续可观测性实战指南
  • 终极指南:如何免费使用Duplicity编辑器修改《缺氧》游戏存档
  • Python实盘组合优化:从cvxpy到PyPortfolioOpt的落地工作流
  • 在Visual Studio 2022里,用C#和OpenTK 4.x画个会转的彩色立方体(附完整代码)
  • 乌鲁木齐驾驶式洗地车2025年度品牌推荐榜 - 工业清洁测评社
  • Embedding实战指南:从词向量到语义搜索的工业级落地
  • CANN图引擎ge核心技术深度解析:从图编译优化到算子融合的昇腾NPU推理性能全链路提升实战
  • Java中String内部排序方法
  • 别再踩坑了!STM32F103C8T6的PB3/PB4/PA15引脚当普通IO口用的完整配置流程(附MDK设置截图)
  • 摘要任务下的RLHF实战:从reward建模到PPO收敛的可复现手记
  • 拆解一个开源四轴:Drone-Mercury硬件选型与成本控制实战分析
  • GPT-4的2%参数真相:MoE稀疏激活原理与工程实践
  • 2026成都工商代办注册公司机构深度盘点:哪家更懂本地中小企业的真实需求? - 优质品牌商家
  • Vue3 Marquee 4.2.2:零依赖动画组件的架构解析与性能优化
  • JWST揭示LRDs光谱多样性及其宇宙学意义
  • 别再死记硬背了!一张图看懂X.25、帧中继、ATM的核心区别与联系