Lambda 表达式是 Java 8 引入的一种新特性,用于简化匿名内部类的写法,支持函数式编程风格。它使代码更加简洁、可读性更强,尤其是在处理集合操作(如排序、过滤等)时非常有用。
一、Lambda 表达式的语法
Lambda 表达式的基本语法如下:
r
(parameters) -> expression
或
ini
(parameters) -> { statements; }
1. 参数部分
- 参数可以有零个、一个或多个。
- 如果只有一个参数且类型可以推断,则可以省略括号和类型声明。例如:
perl
x -> x * x // 等价于 (int x) -> { return x * x; }
- 如果有多个参数,需要用括号包裹,并用逗号分隔。例如:
rust
(x, y) -> x + y
2. 箭头符号 ->
- 箭头符号将参数列表与 Lambda 主体分隔开。
3. Lambda 主体
- 如果主体是一个表达式,则不需要大括号
{}
和return
关键字。例如:
rust
x -> x * x
- 如果主体包含多条语句,则需要用大括号
{}
包裹,并显式使用return
(如果需要返回值)。例如:
ini
(x, y) -> {
int result = x + y;
return result;
}
二、Lambda 表达式的使用场景
Lambda 表达式主要用于实现函数式接口 (Functional Interface)。函数式接口是指只有一个抽象方法的接口。Java 8 提供了大量内置的函数式接口,也可以自定义。
1. 常见的内置函数式接口
接口名称 | 方法签名 | 描述 |
---|---|---|
Runnable |
void run() |
不接受参数,也不返回结果 |
Supplier<T> |
T get() |
不接受参数,返回一个结果 |
Consumer<T> |
void accept(T t) |
接受一个参数,不返回结果 |
Function<T, R> |
R apply(T t) |
接受一个参数,返回一个结果 |
Predicate<T> |
boolean test(T t) |
接受一个参数,返回布尔值 |
Comparator<T> |
int compare(T o1, T o2) |
比较两个对象,返回整数 |
2. 使用示例
(1) Runnable 接口
传统方式:
csharp
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Hello, World!");
}
}).start();
使用 Lambda 表达式:
scss
new Thread(() -> System.out.println("Hello, World!")).start();
(2) Comparator 接口
传统方式:
typescript
Collections.sort(list, new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return s1.compareTo(s2);
}
});
使用 Lambda 表达式:
scss
Collections.sort(list, (s1, s2) -> s1.compareTo(s2));
或者更简洁地使用方法引用:
rust
Collections.sort(list, String::compareTo);
(3) Function 接口
ini
Function<Integer, Integer> square = x -> x * x;
System.out.println(square.apply(5)); // 输出 25
(4) Predicate 接口
ini
Predicate<Integer> isEven = x -> x % 2 == 0;
System.out.println(isEven.test(4)); // 输出 true
System.out.println(isEven.test(5)); // 输出 false
三、Lambda 表达式的优势
- 代码简洁:减少了冗长的匿名内部类写法。
- 提高可读性:逻辑清晰,易于理解。
- 函数式编程支持:方便与流式 API(Stream API)结合使用。
- 延迟执行:Lambda 表达式通常与函数式接口一起使用,可以在需要时才执行逻辑。
四、Lambda 表达式与 Stream API 的结合
Java 8 引入了 Stream API,用于对集合进行高效的操作(如过滤、映射、排序等)。Lambda 表达式是 Stream API 的核心。
1. 示例:过滤和映射
假设有一个整数列表,我们想筛选出偶数并计算它们的平方:
ini
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
List<Integer> result = numbers.stream()
.filter(n -> n % 2 == 0) // 过滤偶数
.map(n -> n * n) // 计算平方
.collect(Collectors.toList());
System.out.println(result); // 输出 [4, 16, 36]
2. 示例:排序
对字符串列表按长度排序:
ini
List<String> words = Arrays.asList("apple", "banana", "cherry");
words.sort((s1, s2) -> Integer.compare(s1.length(), s2.length()));
System.out.println(words); // 输出 [apple, cherry, banana]
五、Lambda 表达式的限制
- 必须实现函数式接口:Lambda 表达式只能用于实现函数式接口,不能直接用于普通接口或类。
- 无法访问非 final 的局部变量 :Lambda 表达式中引用的外部局部变量必须是
final
或"有效 final"(即没有被重新赋值)。
ini
int num = 10; // 有效 final
Runnable r = () -> System.out.println(num);
num = 20; // 编译错误,num 被重新赋值
- 不适合复杂逻辑:对于复杂的业务逻辑,仍然建议使用传统的匿名内部类或方法。
六、总结
Lambda 表达式是 Java 8 中非常重要的特性,它极大地简化了代码编写,特别是在集合操作和函数式编程中发挥着重要作用。通过结合 Stream API 和内置函数式接口,可以使代码更加简洁、灵活和高效。
然而,在使用 Lambda 表达式时需要注意其限制条件,确保代码的可维护性和可读性。