【Java】Lambda 表达式
目录
(AI总结,人工润色)
Java 的 Lambda 表达式。这是一个让 Java 代码变得更简洁、更现代化的强大特性。
一、什么是 Lambda 表达式?
简单来说,Lambda 表达式就是一个可传递的匿名函数。我们可以从三个关键词来理解它:
-
匿名:它没有像普通方法那样有一个明确的名字。
-
函数:它像方法一样,有参数列表、函数体、返回值类型,甚至可能抛出异常。但它不隶属于任何一个特定的类。
-
可传递:Lambda 表达式可以作为参数传递给方法,或者赋值给变量。
它是在 Java 8 中引入的,核心目的是为了简化匿名内部类的书写,尤其是在函数式接口的上下文中。
二、为什么需要 Lambda 表达式?
假设我们有一个场景:需要启动一个新线程来执行一个任务。
1. 传统方式(使用匿名内部类)
在 Java 8 之前,我们得这么写:
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Hello from a thread!");
}
}).start();
我们创建了一个 Runnable 接口的匿名内部类,并重写了 run 方法。虽然功能实现了,但代码非常臃肿,真正核心的代码只有 System.out.println(...) 这一句。
2. 使用 Lambda 表达式
用 Lambda 表达式可以怎么写呢?
new Thread(() -> System.out.println("Hello from a thread!")).start();
是不是瞬间清爽了?() -> System.out.println(...) 就是一个 Lambda 表达式,它完全替代了之前的匿名内部类。
三、Lambda 表达式的语法
Lambda 表达式的语法非常简洁,由三部分组成:
(参数列表) -> { 表达式体 }
让我们来拆解一下:
-
参数列表 (Parameter List): 与要实现的接口中的方法参数列表一致。
-
可以省略参数类型:因为编译器可以通过“上下文”推断出类型,这称为 类型推断。
-
只有一个参数时,可以省略括号
()。
-
-
箭头符号 (Arrow Token):
->,它把参数列表和表达式体分开。 -
表达式体 (Lambda Body): 是要实现的接口方法的具体逻辑。
-
如果表达式体只有一条语句,可以省略大括号
{}和return关键字。 -
如果有多条语句,则必须使用
{}包裹,并且如果需要返回值,必须使用return语句。
-
语法示例:
| 情况 | 示例 | 说明 |
|---|---|---|
| 无参,无返回值 | () -> System.out.println("Hi") | Runnable 接口的完美体现 |
| 一个参数,无返回值 | (s) -> System.out.println(s) | 可简化为 s -> System.out.println(s) |
| 多个参数,无返回值 | (x, y) -> System.out.println(x + y) | |
| 多个参数,有返回值 | (int a, int b) -> { return a + b; } | 标准写法 |
| 多个参数,有返回值(简化) | (a, b) -> a + b | 省略类型、{} 和 return |
四、函数式接口——Lambda 的基础
Lambda 表达式并非在任何地方都能使用,它只能用在 函数式接口 的上下文中。
什么是函数式接口? 它是一个 有且仅有一个抽象方法 的接口。
-
Runnable接口只有一个run()方法,所以它是函数式接口。 -
Comparator接口只有一个compare()方法,所以它也是。 -
Java 8 引入了
@FunctionalInterface注解来标识一个接口是函数式接口。编译器会检查被该注解标记的接口是否确实只有一个抽象方法。
常见的函数式接口:
Java 在 java.util.function 包中内置了很多常用的函数式接口:
| 接口 | 抽象方法 | 描述 | 示例 |
|---|---|---|---|
Consumer<T> | void accept(T t) | 消费者:接收一个参数,无返回值 | (s) -> System.out.println(s) |
Supplier<T> | T get() | 供应者:无参数,返回一个值 | () -> new ArrayList<>() |
Function<T, R> | R apply(T t) | 函数:接收一个参数,返回一个结果 | (s) -> s.length() |
Predicate<T> | boolean test(T t) | 断言:接收一个参数,返回布尔值 | (s) -> s.isEmpty() |
五、Lambda 表达式的应用场景
1. 替换匿名内部类 如上文的 Runnable, Comparator, 事件监听器等。
2. 集合操作(与 Stream API 结合) 这是 Lambda 表达式最强大、最常用的地方。
示例:遍历集合
List<String> list = Arrays.asList("a", "b", "c");
// 传统 for-each 循环
for (String s : list) {
System.out.println(s);
}
// 使用 Lambda 和 forEach 方法
list.forEach(s -> System.out.println(s));
// 更进一步,使用方法引用
list.forEach(System.out::println);
示例:过滤集合
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");
// 过滤出名字以 "A" 开头的
List<String> filtered = names.stream()
.filter(name -> name.startsWith("A")) // Predicate
.collect(Collectors.toList());
// 结果:["Alice"]
示例:映射(转换)集合
List<String> names = Arrays.asList("Alice", "Bob");
// 将每个名字转换为大写
List<String> upperCaseNames = names.stream()
.map(name -> name.toUpperCase()) // Function
.collect(Collectors.toList());
// 结果:["ALICE", "BOB"]
六、方法引用——Lambda 的语法糖
当你需要执行的 Lambda 体恰好是调用一个已有的方法时,你可以使用方法引用,它让代码更加简洁。
语法:目标类或对象::方法名
| 种类 | 语法 | 示例 |
|---|---|---|
| 引用静态方法 | 类名::静态方法 | Math::max 等价于 (a, b) -> Math.max(a, b) |
| 引用特定对象的实例方法 | 对象::实例方法 | System.out::println 等价于 s -> System.out.println(s) |
| 引用任意对象的实例方法 | 类名::实例方法 | String::length 等价于 (s) -> s.length() |
| 引用构造方法 | 类名::new | ArrayList::new 等价于 () -> new ArrayList<>() |
总结
-
核心思想:Lambda 表达式允许你将行为(函数)作为参数进行传递,使代码更简洁、更灵活。
-
基础:Lambda 表达式必须基于函数式接口。
-
语法:
(parameters) -> expression或(parameters) -> { statements; }。 -
最佳搭档:与 Stream API 结合,用于处理集合数据,可以实现强大的声明式编程(告诉你“做什么”,而不是“怎么做”)。
-
进阶技巧:方法引用是 Lambda 的一种更简洁的表示形式。
掌握 Lambda 表达式是现代 Java 开发者的必备技能,它能极大地提升你的编码效率和代码的可读性。
更多推荐


所有评论(0)