Java 8 引入了两个非常重要的特性:Lambda 表达式和Streams API。它们大大简化了代码编写、提高了代码的可读性和可维护性,并使得开发者能够以更声明式的方式处理集合数据。我们将逐一解析这两个特性。
1. Lambda 表达式
1.1 什么是 Lambda 表达式?
Lambda 表达式允许你将函数作为参数传递给方法,或者将其赋值给变量。它主要用于简化匿名内部类的使用,尤其是在处理集合框架时。
Lambda 表达式的基本语法:
(parameters) -> expression
- parameters:方法参数,可以省略类型和括号(当参数只有一个且类型推导明确时)。
- ->:Lambda 运算符,指示方法的实现部分。
- expression:方法体,通常是一个单一的表达式或语句块。
1.2 Lambda 示例
假设有一个列表,你想对其进行排序,传统的做法可能是使用匿名内部类:
List<String> names = Arrays.asList("Tom", "Jerry", "Mickey", "Donald");
Collections.sort(names, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.compareTo(o2);
}
});
在 Java 8 中,使用 Lambda 表达式简化:
Collections.sort(names, (s1, s2) -> s1.compareTo(s2));
更简洁的写法:
names.sort((s1, s2) -> s1.compareTo(s2));
1.3 Lambda 表达式的优势
- 减少冗余代码:避免了匿名内部类的复杂写法。
- 可读性提高:代码更加简洁、直观。
- 更高效的并行化:与 Streams API 配合,能够更容易地实现并行计算。
2. Streams API
2.1 什么是 Streams?
Streams API 允许你以声明式的方式处理数据集合。通过流(Stream)对象,Java 8 引入了一种新的方式来遍历、过滤、转换集合中的数据,甚至可以进行并行计算。
Stream 是一个包含数据的对象,通过流操作可以高效地处理这些数据。它的操作是惰性求值的,即只有当你真正需要结果时,才会执行操作。
2.2 Stream 的常用操作
Streams 支持多种操作,通常分为两类:
- 中间操作:返回新的 Stream,本身不会修改源数据。
- 终止操作:对 Stream 中的数据进行处理,通常会返回一个结果或者副作用。
2.3 中间操作示例
- filter:筛选符合条件的元素。
- map:将元素转换为其他形式。
- distinct:去重。
- sorted:排序。
List<String> names = Arrays.asList("Tom", "Jerry", "Mickey", "Donald", "Jerry");
List<String> result = names.stream()
.filter(name -> name.startsWith("J")) // 过滤以 "J" 开头的名字
.distinct() // 去重
.sorted() // 排序
.collect(Collectors.toList()); // 转换为 List
2.4 终止操作示例
- forEach:遍历每个元素。
- reduce:将流中的元素结合起来,生成一个单一的结果。
- collect:将流中的元素收集成集合、列表、映射等。
// 输出以 "J" 开头的所有名字
names.stream()
.filter(name -> name.startsWith("J"))
.forEach(System.out::println);
// 计算所有名字的总长度
int totalLength = names.stream()
.mapToInt(String::length)
.sum();
2.5 并行流
Stream 支持并行处理数据。通过调用 parallelStream()
方法,Java 会自动将流中的数据分配到多个线程进行处理,利用多核 CPU 提升性能。
List<String> names = Arrays.asList("Tom", "Jerry", "Mickey", "Donald", "Jerry");
names.parallelStream()
.filter(name -> name.startsWith("J"))
.forEach(System.out::println);
2.6 Stream 连接 Lambda 表达式
Stream API 与 Lambda 表达式密切相关,Stream API 中许多操作都使用了 Lambda 表达式来处理数据。
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 使用 map 和 Lambda 表达式将每个数字平方
List<Integer> squared = numbers.stream()
.map(n -> n * n) // Lambda 表达式
.collect(Collectors.toList());
System.out.println(squared); // 输出 [1, 4, 9, 16, 25]
2.7 常见的 Collector 工具类
Collectors
是一个辅助类,提供了许多静态方法,用于将 Stream 中的元素收集成集合、字符串等。
List<String> names = Arrays.asList("Tom", "Jerry", "Mickey", "Donald");
// 将名字合并成一个字符串
String result = names.stream()
.collect(Collectors.joining(", "));
System.out.println(result); // 输出 Tom, Jerry, Mickey, Donald
3. 结合使用:Lambda + Stream
Lambda 表达式和 Stream API 常常一起使用,能够以非常简洁和直观的方式对集合进行复杂的操作。
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// 使用 Stream 过滤偶数,平方后输出
numbers.stream()
.filter(n -> n % 2 == 0) // 过滤偶数
.map(n -> n * n) // 平方
.forEach(System.out::println); // 输出
4. 总结
- Lambda 表达式:使代码更加简洁、易读。它主要用于简化代码,尤其是匿名内部类的使用。
- Streams API:通过声明式的操作方式,提供了更加灵活和强大的数据处理能力。支持过滤、映射、排序、聚合等操作,甚至可以并行化处理数据