Java中函数式编程思想
课时:90分钟
教学目标:
-
理解函数式编程的核心概念与设计思想
-
掌握Java中Lambda表达式、函数式接口与Stream API的用法
-
能够通过函数式编程简化代码并提升可维护性
-
结合实战案例实现高效的数据处理与业务逻辑
一、课程引入
1.1 函数式编程的核心思想
-
纯函数:相同输入始终产生相同输出,无副作用
-
不可变数据:避免状态修改,减少并发问题
-
高阶函数:函数作为参数或返回值
1.2 Java函数式编程演进
版本 | 特性 |
---|---|
Java 8 | Lambda、Stream、函数式接口 |
Java 11 | var 局部变量类型推断 |
Java 16 | 模式匹配增强 |
二、Lambda表达式与函数式接口
2.1 Lambda表达式语法
java
复制
(参数列表) -> { 代码块 } // 示例 Runnable task = () -> System.out.println("Hello Lambda"); Comparator<Integer> cmp = (a, b) -> a - b;
2.2 内置函数式接口
接口 | 方法 | 用途 |
---|---|---|
Supplier<T> | T get() | 无参返回结果 |
Consumer<T> | void accept(T) | 消费一个参数 |
Function<T,R> | R apply(T) | 转换输入为输出 |
Predicate<T> | boolean test(T) | 条件判断 |
案例1:自定义条件过滤
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> evenNumbers = numbers.stream()
.filter(n -> n % 2 == 0)
.collect(Collectors.toList());
// [2, 4]
三、方法引用与构造器引用
3.1 方法引用类型
类型 | 语法 | 示例 |
---|---|---|
静态方法引用 | 类名::方法名 | Math::sqrt |
实例方法引用 | 对象::方法名 | System.out::println |
任意对象方法引用 | 类名::方法名 | String::length |
案例2:排序优化
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
names.sort(String::compareToIgnoreCase);
// [Alice, Bob, Charlie]
3.2 构造器引用
Supplier<List<String>> listSupplier = ArrayList::new;
List<String> list = listSupplier.get();
四、Stream API高级应用
4.1 中间操作与终止操作
操作类型 | 方法示例 | 说明 |
---|---|---|
中间操作 | filter() , map() , sorted() | 生成新Stream,延迟执行 |
终止操作 | collect() , forEach() , count() | 触发计算,返回结果 |
4.2 并行流与性能优化
案例3:大数据集并行处理
List<Integer> bigList = IntStream.range(0, 1_000_000).boxed().collect(Collectors.toList());
long count = bigList.parallelStream()
.filter(n -> n % 3 == 0)
.count();
System.out.println("能被3整除的数数量:" + count);
4.3 复杂数据转换
案例4:订单金额统计
List<Order> orders = getOrders();
Map<String, Double> totalByCategory = orders.stream()
.collect(Collectors.groupingBy(
Order::getCategory,
Collectors.summingDouble(Order::getAmount)
));
// 输出:{电子=15000.0, 服装=5000.0}
五、函数式编程实战
5.1 案例5:事件监听器简化
// 传统写法
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("按钮被点击");
}
});
// Lambda写法
button.addActionListener(e -> System.out.println("按钮被点击"));
5.2 案例6:自定义高阶函数
public static <T> List<T> filterList(List<T> list, Predicate<T> predicate) {
return list.stream().filter(predicate).collect(Collectors.toList());
}
// 使用
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> even = filterList(numbers, n -> n % 2 == 0);
5.3 案例7:函数链式处理
Function<String, String> addHeader = s -> "Header: " + s;
Function<String, String> addFooter = s -> s + " Footer";
Function<String, String> process = addHeader.andThen(addFooter);
String result = process.apply("Main Content");
// Header: Main Content Footer
六、常见问题与最佳实践
6.1 常见陷阱
-
副作用问题:
List<Integer> list = new ArrayList<>(); numbers.forEach(n -> list.add(n)); // 违反纯函数原则,可能引发并发问题
-
无限流处理:
Stream.generate(Math::random).forEach(System.out::println); // 无限循环
6.2 最佳实践
-
优先使用无状态操作:如
map
、filter
-
避免在Lambda中修改外部状态
-
合理使用并行流:数据量大且无共享状态时使用
七、总结与练习
7.1 总结
-
核心工具:Lambda、Stream、函数式接口
-
优势:代码简洁、易于并行、高可读性
-
适用场景:集合处理、事件驱动、数据流水线
7.2 课后任务
-
使用Stream API统计一段文本中每个单词的出现频率
-
用Lambda重构传统匿名内部类代码(如线程、比较器)
-
预习下一节课:Java模块化系统
7.3 扩展挑战
-
实现一个基于函数式编程的订单处理系统(过滤、转换、聚合)