Lambda 表达式是 Java 8 引入的一项重要特性,它提供了一种简洁的方式来表示匿名函数。Lambda 表达式主要用于简化函数式接口的实现,使代码更加简洁和易读。以下是关于 Lambda 表达式的详细阐述:
1. Lambda 表达式的基本语法
Lambda 表达式的语法如下:
(parameter_list) -> { 代码块 }
parameter_list
:参数列表,可以包含零个或多个参数,参数类型可以省略(由编译器自动推断)。->
:Lambda 操作符,将参数列表与 Lambda 主体分隔开。代码块
:Lambda 主体,包含实现函数式接口的代码。如果只有一行代码,可以省略{}
和return
语句。
示例:
// 无参数
() -> System.out.println("Hello, World!");
// 单个参数
(x) -> x * x;
// 多个参数
(x, y) -> x + y;
// 带代码块
(x, y) -> {
int sum = x + y;
return sum;
};
2. 函数式接口
Lambda 表达式的核心是函数式接口(Functional Interface)。函数式接口是指 仅包含一个抽象方法 的接口。Java 提供了 @FunctionalInterface
注解来标记函数式接口。
常见的函数式接口:
Runnable
:void run()
Consumer<T>
:void accept(T t)
Supplier<T>
:T get()
Function<T, R>
:R apply(T t)
Predicate<T>
:boolean test(T t)
示例:
@FunctionalInterface
interface MyInterface {
void doSomething();
}
// 使用 Lambda 表达式实现函数式接口
MyInterface myLambda = () -> System.out.println("Doing something");
myLambda.doSomething();
好好体会一下,lambda式是一个函数,他赋值给一个接口变量,那么这个接口一定要有一个抽象方法去实现,正好把lambda的这个函数赋值给这个未被重写的抽象类;而且这个接口一定只能有一个未实现方法,为什么呢,因为如果有多个,谁也分不清楚给哪个方法;有点意思!
3. Lambda 表达式的使用场景
(1) 简化匿名内部类
Lambda 表达式可以替代匿名内部类,使代码更简洁。
// 传统匿名内部类
Runnable r1 = new Runnable() {
@Override
public void run() {
System.out.println("Hello, World!");
}
};
// 使用 Lambda 表达式
Runnable r2 = () -> System.out.println("Hello, World!");
注意:以上代码中Runnable 就只是一个普通的函数式接口,只是起到举例子的效果,可以替换成自定义函数式接口
(2) 遍历集合
Lambda 表达式结合 forEach()
方法可以简化集合的遍历操作。
List<String> list = Arrays.asList("Apple", "Banana", "Orange");
// 传统遍历
for (String s : list) {
System.out.println(s);
}
// 使用 Lambda 表达式
list.forEach(s -> System.out.println(s));
(3) 作为方法参数
Lambda 表达式可以作为方法参数传递,特别适合用于需要回调函数的场景。
public static void processList(List<String> list, Consumer<String> consumer) {
for (String s : list) {
consumer.accept(s);
}
}
// 调用方法
processList(list, s -> System.out.println(s));
(4) 结合 Stream API
Lambda 表达式与 Stream API 结合,可以实现强大的数据处理功能,如过滤、映射、排序等。
List<String> fruits = Arrays.asList("Apple", "Banana", "Orange", "Mango");
// 过滤长度大于 5 的字符串
List<String> filtered = fruits.stream()
.filter(s -> s.length() > 5)
.collect(Collectors.toList());
// 将字符串转换为大写
List<String> upperCase = fruits.stream()
.map(s -> s.toUpperCase())
.collect(Collectors.toList());
4. Lambda 表达式的变量作用域
Lambda 表达式可以访问外部的局部变量、实例变量和静态变量,但有如下限制:
- 局部变量:Lambda 表达式访问的局部变量必须是
final
或实际上是final
的(即不可变)。 - 实例变量和静态变量:Lambda 表达式可以访问并修改实例变量和静态变量。
示例:
int num = 10; // 局部变量
Runnable r = () -> System.out.println(num); // num 必须是 final 或 effectively final
// 错误示例
int num2 = 20;
num2 = 30; // 修改 num2
Runnable r2 = () -> System.out.println(num2); // 编译错误:num2 必须是 final
5. 方法引用
方法引用是 Lambda 表达式的一种简化形式,用于直接引用已有的方法。方法引用的语法如下:
类名::方法名
方法引用的四种形式:
- 静态方法引用:
ClassName::staticMethod
- 实例方法引用:
instance::instanceMethod
- 特定类型的任意对象方法引用:
ClassName::instanceMethod
- 构造方法引用:
ClassName::new
示例:
List<String> list = Arrays.asList("Apple", "Banana", "Orange");
// 使用 Lambda 表达式
list.forEach(s -> System.out.println(s));
// 使用方法引用
list.forEach(System.out::println);
好好理解上面的例子,还挺有意思,但是挺无聊;
感觉就是,有一个类他有很多方法,但是我就想要他的其中一个方法。。。。就是为了这个;
6. 注意事项
- 简洁性:Lambda 表达式应尽量保持简洁,避免过于复杂的逻辑。
- 可读性:如果 Lambda 表达式过长或逻辑复杂,应考虑使用命名方法代替。
- 性能:Lambda 表达式的性能与传统方式相当,但在某些情况下可能会有轻微的开销。
总结
Lambda 表达式是 Java 8 引入的一项重要特性,它通过简化函数式接口的实现,使代码更加简洁和易读。Lambda 表达式广泛应用于集合遍历、Stream API、回调函数等场景。掌握 Lambda 表达式及其相关特性(如方法引用、函数式接口),可以显著提升 Java 开发效率和代码质量。