编程自学指南:java程序设计开发,Lambda表达式与Stream API
学习目标:
-
理解Lambda表达式的语法与函数式编程思想
-
掌握Stream API的核心操作(过滤、映射、归约)
-
能够通过Lambda与Stream简化集合数据处理
-
结合实战案例提升代码简洁性与可读性
一、课程引入
1.1 为什么需要Lambda与Stream?
-
传统写法痛点:
// 匿名内部类冗长 button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { System.out.println("按钮被点击"); } });
Lambda优势:
-
代码简洁
-
函数式编程支持
-
便于并行处理
-
1.2 函数式接口(Functional Interface)
-
定义:仅含一个抽象方法的接口(如
Runnable
,Comparator
) -
注解:
@FunctionalInterface
二、Lambda表达式
2.1 基础语法
(参数列表) -> { 代码块 }
案例1:替代匿名内部类
// 传统写法
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("线程运行");
}
}).start();
// Lambda写法
new Thread(() -> System.out.println("线程运行")).start();
2.2 Lambda简化形式
场景 | 示例 |
---|---|
无参数 | () -> System.out.println() |
单参数类型推断 | s -> System.out.println(s) |
多参数 | (a, b) -> a + b |
代码块多行 | (x, y) -> { return x > y; } |
案例2:集合排序
List<String> names = Arrays.asList("Tom", "Alice", "Bob");
// 传统写法
names.sort(new Comparator<String>() {
@Override
public int compare(String a, String b) {
return a.compareTo(b);
}
});
// Lambda写法
names.sort((a, b) -> a.compareTo(b));
// 方法引用进一步简化
names.sort(String::compareTo);
三、Stream API
3.1 Stream特性
-
不存储数据:仅对源数据计算
-
不修改源数据:生成新Stream
-
延迟执行:终端操作触发计算
3.2 Stream操作分类
操作类型 | 方法示例 | 说明 |
---|---|---|
中间操作 | filter() , map() , sorted() | 生成新Stream,可链式调用 |
终端操作 | forEach() , collect() , count() | 触发计算,返回结果 |
3.3 核心操作示例
案例3:过滤与映射
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> squares = numbers.stream()
.filter(n -> n % 2 == 0) // 过滤偶数
.map(n -> n * n) // 平方
.collect(Collectors.toList()); // 收集结果
System.out.println(squares); // [4, 16]
案例4:归约与统计
// 求和
int sum = numbers.stream().reduce(0, Integer::sum);
// 统计
IntSummaryStatistics stats = numbers.stream()
.mapToInt(x -> x)
.summaryStatistics();
System.out.println("平均值:" + stats.getAverage());
3.4 并行流
案例5:并行计算加速
long count = numbers.parallelStream()
.filter(n -> n > 2)
.count();
四、综合应用
4.1 案例6:员工数据处理
public class Employee {
private String name;
private int salary;
private String department;
// 构造方法、getter/setter
}
List<Employee> employees = Arrays.asList(
new Employee("张三", 8000, "技术部"),
new Employee("李四", 12000, "技术部"),
new Employee("王五", 9000, "市场部")
);
// 按部门分组,统计平均工资
Map<String, Double> avgSalaryByDept = employees.stream()
.collect(Collectors.groupingBy(
Employee::getDepartment,
Collectors.averagingInt(Employee::getSalary)
));
// 输出:{技术部=10000.0, 市场部=9000.0}
4.2 案例7:文本处理
String text = "Java Lambda Stream API";
// 统计单词长度大于3的词频
Map<String, Long> wordCount = Arrays.stream(text.split(" "))
.filter(word -> word.length() > 3)
.collect(Collectors.groupingBy(
String::toLowerCase,
Collectors.counting()
));
// 输出:{lambda=1, stream=1, api=1}
五、常见错误与最佳实践
5.1 常见错误
-
错误1:重复使用Stream
Stream<Integer> stream = numbers.stream(); stream.filter(n -> n > 2); stream.count(); // 抛出IllegalStateException
- 错误2:在Lambda中修改外部变量
int count = 0;
numbers.forEach(n -> count++); // 编译错误:变量需为final或等效final
5.2 最佳实践
-
优先使用方法引用:
System.out::println
替代x -> System.out.println(x)
-
避免复杂Lambda:若逻辑超过3行,考虑封装为方法
-
并行流慎用:数据量大且无状态操作时使用
六、总结与学习
6.1 总结
-
Lambda:简化匿名内部类,支持函数式编程
-
Stream:链式操作处理集合数据,支持并行
6.2 课后任务
-
使用Stream API实现以下功能:
-
从一个整数列表中找出所有质数
-
将字符串列表按长度排序
-
-
用Lambda改写之前课程中的多线程示例(如Runnable实现)
-
预习下一节课:新特性(Optional、时间API)
6.3 扩展挑战
-
用Stream API实现一个简单的股票交易分析系统(按价格、交易量过滤数据)