Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

第 7 周:Lambda、方法引用与 Stream

本周目标

本周学会 JDK 8 之后的现代 Java 写法。完成后,应能够:

  • 使用函数式接口和 Lambda 表达式替代匿名内部类
  • 使用方法引用简化 Lambda
  • 使用 Stream 完成过滤、映射、排序、去重和截取
  • 使用 collect() 把流结果收集为 List、Set、Map 和字符串
  • 使用分组、分区和聚合完成统计报表
  • 使用不可变集合避免意外修改

学习资料与范围

学习模块学习结果
函数式接口与 Lambda 表达式能够用 Lambda 替代匿名内部类
方法引用与构造器引用能够判断何时使用方法引用
Stream 的创建、中间操作和终结操作能够写出完整的数据处理流水线
收集结果与聚合统计能够收集为集合、字符串和统计结果
不可变集合能够创建并使用不可变集合

需要掌握的知识点

函数式编程基础

  • 函数式接口的概念和 @FunctionalInterface
  • Consumer、Supplier、Function、Predicate 的用途和泛型含义
  • Lambda 的语法、参数和返回值推断规则
  • 匿名内部类与 Lambda 的写法对比
  • 方法引用的四种形式:静态方法、实例方法、对象方法、构造器引用
  • 变量捕获限制:Lambda 中使用的外部局部变量必须是 final 或事实 final

Stream 基础

  • Stream 与集合的区别:集合存数据,流处理数据
  • 三步结构:创建流、中间操作、终结操作
  • 创建流的方式:集合 stream()、数组 Arrays.stream()、Stream.of()
  • 中间操作:filter、map、distinct、sorted、limit、skip、flatMap
  • 终结操作:forEach、count、collect、reduce、max、min
  • 惰性求值:中间操作不执行,终结操作才触发
  • 流只能消费一次,重复使用会抛异常

收集与统计

  • collect(Collectors.toList())、toSet()、toMap()
  • toMap() 的键冲突问题和解决方式
  • groupingBy() 分组、partitioningBy() 分区
  • counting()、summingDouble()、averagingDouble() 等下游收集器
  • joining() 拼接字符串并处理分隔符、前缀和后缀
  • sorted() 结合 Comparator 实现内存排序
  • 数值流 mapToInt()、mapToDouble() 与 sum()、average()、summaryStatistics()

不可变集合与使用原则

  • List.of()、Set.of()、Map.of() 和 List.copyOf() 的特点
  • 不可变集合的修改报错和适用场景(常量、返回值保护)
  • Stream 代码的可读性边界:逻辑复杂时保留传统循环
  • 调试 Stream 链路的方法:拆分中间变量、先看中间结果

必做练习

  1. 匿名内部类改造:把 Comparator 与 Runnable 的匿名内部类改写为 Lambda。
  2. 方法引用:把筛选、打印和构造学生对象的 Lambda 改写为方法引用,并说明选择理由。
  3. 筛选与映射:从学生列表中筛选出及格学生,映射为“姓名:总分”的字符串列表。
  4. 去重与排序:对班级名称去重并按名称排序输出。
  5. 对照练习:分别用循环和 Stream 实现同一统计需求,写出两种版本的代码并对比可读性。
  6. 收集为 Map:把学生列表收集为学号到学生的 Map,处理重复学号冲突。
  7. 分组统计:使用 groupingBy() 统计每班人数和平均分。
  8. 聚合统计:使用 summaryStatistics() 输出成绩的个数、总和、平均值、最大值和最小值。
  9. 排名报表:按总分降序取前三名,使用 joining() 拼成多行文本并写入报表文件。
  10. 不可变集合:使用不可变集合保存班级名称常量,并记录一次修改失败的过程。
  11. 边界处理:统计空集合和全为不及格成绩时不出现除零或空指针异常。

本周综合任务:用 Stream 重写统计报表模块

把项目中的查询和统计方法改写为 Stream 写法,输出一份控制台报表。

要求:

  • 使用 Stream 替换遍历加条件判断的统计代码
  • 报表内容至少包含:班级人数、班级平均分、及格率、总分前三名、各科平均分
  • 使用 groupingBy() 加下游收集器完成分组统计,不使用多层嵌套循环
  • 使用 Comparator 和 sorted() 完成排名,复用第 6 周提取的比较器
  • 使用 joining() 生成对齐的文本报表,并保存为文件
  • 至少保留一处传统循环写法,并在注释中说明保留原因
  • 为每个统计方法补充单元测试,覆盖正常数据和空数据两种情况

本周产出

  • Lambda 与方法引用练习代码
  • Stream 常用操作练习代码
  • 统计报表模块及生成的报表文件
  • 循环版与 Stream 版对照代码
  • 一份 Stream 常用方法速查笔记

完成检查

  • 能够使用函数式接口和 Lambda 替代匿名内部类
  • 能够识别并使用四种方法引用形式
  • 能够写出创建、中间操作、终结操作完整的流处理链
  • 能够把流结果收集为 List、Set、Map 和字符串
  • 能够使用分组、分区和聚合完成统计
  • 能够使用不可变集合保护数据
  • 能够判断何时不适合使用 Stream
  • 已完成统计报表模块的 Stream 改写并通过测试