目录

一、什么是 Lambda 表达式?

二、为什么需要 Lambda 表达式?

三、Lambda 表达式的语法

四、函数式接口——Lambda 的基础

五、Lambda 表达式的应用场景

六、方法引用——Lambda 的语法糖

总结


(AI总结,人工润色)

Java 的 Lambda 表达式。这是一个让 Java 代码变得更简洁、更现代化的强大特性。

一、什么是 Lambda 表达式?

简单来说,Lambda 表达式就是一个可传递的匿名函数。我们可以从三个关键词来理解它:

  1. 匿名:它没有像普通方法那样有一个明确的名字。

  2. 函数:它像方法一样,有参数列表、函数体、返回值类型,甚至可能抛出异常。但它不隶属于任何一个特定的类。

  3. 可传递: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()
引用构造方法类名::newArrayList::new 等价于 () -> new ArrayList<>()

总结

  • 核心思想:Lambda 表达式允许你将行为(函数)作为参数进行传递,使代码更简洁、更灵活。

  • 基础:Lambda 表达式必须基于函数式接口

  • 语法(parameters) -> expression(parameters) -> { statements; }

  • 最佳搭档:与 Stream API 结合,用于处理集合数据,可以实现强大的声明式编程(告诉你“做什么”,而不是“怎么做”)。

  • 进阶技巧方法引用是 Lambda 的一种更简洁的表示形式。

掌握 Lambda 表达式是现代 Java 开发者的必备技能,它能极大地提升你的编码效率和代码的可读性。

更多推荐