Java 8 中引入的 Lambda 表达式极大地改善了 Java 的简洁性和可读性,特别是用于处理集合、流操作等场景。
Lambda 表达式可以看作是用来简化匿名内部类的一种简写方式。它可以直接作为接口实现被传递。Java 中,很多接口有且只有一个抽象方法,这些接口被称为 函数式接口(Functional Interface)。例如 java.lang.Runnable
和 java.util.function
包中的接口,如 Predicate
、Consumer
等。
- Lambda 表达式的基本语法
- 【示例 1】使用 Runnable 接口
- 【示例 2】使用 Comparator 接口
- Java 内置的函数式接口
- 【示例 3】使用 Predicate
- 【示例 4】使用 Consumer
- Stream API 与 Lambda 表达式结合使用
- 【示例 5】Stream API 的使用
- Lambda 表达式的常用场景
Lambda 表达式的基本语法
(parameters) -> expression
或
(parameters) -> { statements; }
- 参数列表:列出传递给 Lambda 表达式的参数,多个参数用逗号分隔。如果参数类型可以从上下文推断,则可以省略类型。
-
箭头符号:
->
,用来分隔参数列表和 Lambda 表达式主体。 -
表达式或代码块:如果是单个表达式,结果会被自动返回。如果是多条语句,则需要使用大括号
{}
。
【示例 1】使用 Runnable 接口
传统上,使用匿名类来实现 Runnable
接口:
Runnable r1 = new Runnable() {
@Override
public void run() {
System.out.println("Hello from Runnable using anonymous class!");
}
};
new Thread(r1).start();
使用 Lambda 表达式后,代码可以简化为:
Runnable r2 = () -> System.out.println("Hello from Runnable using Lambda!");
new Thread(r2).start();
或者更进一步:
new Thread(() -> System.out.println("Hello from Runnable using Lambda!")).start();
【示例 2】使用 Comparator 接口
假设我们有一个 List<String>
,想对其进行排序,传统方式是使用匿名类实现 Comparator
:
List<String> names = Arrays.asList("John", "Alice", "Bob");
Collections.sort(names, new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return s1.compareTo(s2);
}
});
使用 Lambda 表达式后可以简化为:
Collections.sort(names, (s1, s2) -> s1.compareTo(s2));
进一步,我们可以直接使用 List
的 sort
方法:
names.sort((s1, s2) -> s1.compareTo(s2));
Java 8 还提供了更简洁的方式,利用方法引用:
names.sort(String::compareTo);
Java 内置的函数式接口
Java 8 引入了 java.util.function
包,包含一些常用的函数式接口,例如:
-
Predicate:接受一个参数,返回一个布尔值 (
boolean
)。 - Consumer:接受一个参数,没有返回值。
- Function<T, R>:接受一个参数,返回一个结果。
- Supplier:没有参数,返回一个结果。
下面举一些使用这些函数式接口的例子:
【示例 3】使用 Predicate
假设我们想过滤一个整数列表,得到所有大于 5 的值,传统方式可能会这样写:
List<Integer> numbers = Arrays.asList(1, 2, 3, 6, 8, 10);
List<Integer> filteredNumbers = new ArrayList<>();
for (Integer number : numbers) {
if (number > 5) {
filteredNumbers.add(number);
}
}
使用 Lambda 表达式和 Predicate
接口可以这样写:
List<Integer> numbers = Arrays.asList(1, 2, 3, 6, 8, 10);
List<Integer> filteredNumbers = numbers.stream()
.filter(n -> n > 5)
.collect(Collectors.toList());
System.out.println(filteredNumbers); // 输出: [6, 8, 10]
【示例 4】使用 Consumer
假设我们需要对一个列表的每个元素执行某些操作,比如打印它们:
List<String> names = Arrays.asList("John", "Alice", "Bob");
// 使用 Lambda 表达式
names.forEach(name -> System.out.println(name));
// 使用方法引用
names.forEach(System.out::println);
Stream API 与 Lambda 表达式结合使用
Stream API 提供了一种函数式的编程方式来处理集合数据。
【示例 5】Stream API 的使用
假设我们有一个 List<String>
,需要对其进行一系列操作:过滤掉长度小于 4 的字符串,将它们转换为大写,并收集到一个新的列表中。
List<String> names = Arrays.asList("John", "Alice", "Bob", "David");
List<String> filteredNames = names.stream() // 创建 Stream
.filter(name -> name.length() > 3) // 过滤长度大于 3 的名字
.map(String::toUpperCase) // 转换为大写
.collect(Collectors.toList()); // 收集结果
System.out.println(filteredNames); // 输出: [JOHN, ALICE, DAVID]
在这个例子中,filter
、map
等方法都使用了 Lambda 表达式。
Lambda 表达式的常用场景
- 集合操作:如排序、过滤、转换等。
-
异步编程:如简化
Runnable
、Callable
等接口的实现。 - 事件处理:Lambda 非常适合用于 GUI 或者回调事件中,减少了编写事件监听器的样板代码。