JAVA重点基础、进阶知识及易错点总结(26)Stream 流式编程
Java 巩固进阶 · 第 26 天主题Stream 流式编程 —— 集合处理的革命 进度概览继昨天 Lambda 表达式之后今天进入JDK8 最重量级特性Stream API。它将函数式编程思想引入集合处理让代码像 SQL 一样声明式地操作数据。 核心价值声明式编程关注做什么而非怎么做代码可读性提升 50%。链式调用多个操作串联避免中间变量逻辑流畅。内部迭代Stream 内部优化迭代逻辑便于未来并行化parallelStream。框架基石Spring Data、MyBatis 结果处理、日常业务数据清洗都离不开它。一、Stream 本质数据处理的管道 1. 什么是 Stream┌─────────────────────────────────────┐ │ Stream 核心特性 │ │ │ │ • 不存储数据只是数据源的视图 │ │ • 不修改源数据返回新 Stream │ │ • 懒加载中间操作不执行直到终止 │ │ • 一次性Stream 只能用一次 │ └─────────────────────────────────────┘2. 操作流程图解数据源 (Collection/Array) ↓ 创建 Stream (stream()) ↓ 中间操作 (filter/map/sorted) → 懒加载不执行 ↓ 终止操作 (collect/forEach/count) → 触发执行 ↓ 结果 (List/Value/void)一句话理解“Stream 就像工厂流水线数据是原材料中间操作是加工环节终止操作是成品出库”二、核心 API 实战创建与操作 ️1. 创建 Stream 的 4 种方式// 1. 集合创建最常用ListStringlistArrays.asList(a,b,c);StreamStringstreamlist.stream();// 2. 数组创建String[]arr{x,y,z};StreamStringstreamArrays.stream(arr);// 3. 静态方法创建StreamStringstreamStream.of(m,n,o);// 4. 无限流生成随机数/序列StreamDoublerandomStream.generate(Math::random);StreamIntegerrangeStream.iterate(0,n-n1);2. 常用中间操作Intermediate// ✅ filter过滤stream.filter(s-s.length()3);// ✅ map转换一对一stream.map(String::toUpperCase);// ✅ flatMap扁平化一对多如 ListList 转 Liststream.flatMap(list-list.stream());// ✅ sorted排序stream.sorted(Comparator.naturalOrder());stream.sorted((a,b)-b-a);// 降序// ✅ distinct去重依赖 hashCode/equalsstream.distinct();// ✅ limit/skip截取/跳过stream.limit(5);stream.skip(2);3. 常用终止操作Terminal// ✅ 收集结果最常用ListStringcollectedstream.collect(Collectors.toList());SetStringsetstream.collect(Collectors.toSet());MapString,Integermapstream.collect(Collectors.toMap(k-k,v-v.length()));// ✅ 统计/查找longcountstream.count();OptionalStringmaxstream.max(Comparator.naturalOrder());booleananyMatchstream.anyMatch(s-s.startsWith(A));// ✅ 遍历消费stream.forEach(System.out::println);⚠️关键陷阱Stream 不能复用StreamStringslist.stream();s.forEach(...);// 第一次使用s.filter(...);// ❌ 报错Stream has already been operated upon or closed三、Collectors 工具类数据汇总神器 1. 常用收集器// 1. 转集合list.stream().collect(Collectors.toList());// 2. 转字符串拼接Stringstrlist.stream().collect(Collectors.joining(, ));// a, b, c// 3. 分组类似 SQL GROUP BYMapInteger,ListUserbyAgeusers.stream().collect(Collectors.groupingBy(User::getAge));// 4. 分区类似 SQL CASE WHEN分为 true/false 两组MapBoolean,ListUserbyAdultusers.stream().collect(Collectors.partitioningBy(u-u.getAge()18));// 5. 统计数值IntSummaryStatisticsIntSummaryStatisticsstatsusers.stream().collect(Collectors.summarizingInt(User::getSalary));System.out.println(平均薪资stats.getAverage());2. 并行流Parallel Stream// ✅ 一键并行利用多核 CPUlist.parallelStream().filter(...).collect(...);// ⚠️ 注意// 1. 线程不安全collect 需用 Collectors.toConcurrentMap 或 synchronized// 2. 性能陷阱数据量小时线程切换开销可能比串行还慢// 3. 顺序问题parallelStream 不保证顺序需用 ordered()四、 今日实战任务用户数据处理系统任务 1基础筛选与转换/** * 业务场景筛选成年男性用户并提取姓名 * * 要求 * 1. 创建用户列表包含姓名、年龄、性别、薪资 * 2. 用 Stream 筛选年龄18 且 性别为男 * 3. 映射只保留姓名 * 4. 收集转为 ListString * * 提示 * .filter(u - u.getAge() 18 u.getGender() MALE) * .map(User::getName) * .collect(Collectors.toList()) */任务 2复杂排序与去重/** * 业务场景薪资排行榜 * * 要求 * 1. 按薪资降序排序 * 2. 如果薪资相同按年龄升序 * 3. 去除重复用户假设重写 equals * 4. 取前 3 名 * * 挑战 * - 使用 Comparator.thenComparing() 实现链式排序 * - 使用 distinct() 去重 */任务 3数据分组统计/** * 业务场景部门薪资统计 * * 要求 * 1. 按部门分组MapDepartment, ListUser * 2. 计算每个部门的平均薪资 * 3. 计算每个部门的最高薪资 * * 关键 API * Collectors.groupingBy(..., Collectors.averagingDouble(...)) */任务 4性能对比实验/** * 要求 * 1. 创建 100 万条数据的 List * 2. 用传统 for 循环筛选并计数 * 3. 用 Stream 筛选并计数 * 4. 用 parallelStream 筛选并计数 * 5. 对比三者耗时注意预热 JVM * * 思考 * - 什么场景下 parallelStream 更快 * - 为什么小数据量不建议用并行流 */ 第 26 天 · 核心总结极简背诵版Stream 三要素创建 → 中间操作懒加载 → 终止操作触发执行 不可复用不改源数据常用操作链list.stream().filter(...)// 过滤.map(...)// 转换.sorted(...)// 排序.collect(...)// 收集Collectors 核心toList / toSet / toMap groupingBy分组 joining拼接 summarizingInt统计并行流注意事项✅ 大数据量 CPU 密集型任务❌ 小数据量 IO 密集型任务⚠️ 注意线程安全问题明天预告️Optional 类 —— 优雅解决空指针为什么 NPE 是 Java 十亿美元错误Optional 核心方法of, ofNullable, orElse链式调用中的空值处理实战嵌套对象的安全访问准备好了吗明天我们彻底告别if (obj ! null) ✨