源本科技 | 码上会

Java Lambda 表达式

2026/01/29
52
0

学习目标

  • 理解 Lambda 表达式的基本概念及其在 Java 中的作用

  • 掌握 Lambda 表达式的语法结构与参数类型

  • 学会将 Lambda 表达式应用于函数式接口、集合和流操作

  • 了解常用内置函数式接口(如 Predicate、Consumer 等)的用途

  • 能够判断 Lambda 表达式的合法性并避免常见错误


什么是 Lambda

Lambda 表达式是 Java 8 引入的一项重要特性,它允许开发者以简洁的方式编写函数式风格的代码。本质上,Lambda 表达式是一种匿名函数,可以像数据一样被传递或赋值给变量,从而显著提升代码的可读性和简洁性。

Lambda 表达式必须实现一个函数式接口——即只包含一个抽象方法的接口。通过 Lambda,我们可以直接提供该抽象方法的实现,而无需显式定义类或匿名内部类。

基本示例

interface Add {
    int addition(int a, int b);
}

public class Main {
    public static void main(String[] args) {
        // 使用 Lambda 表达式实现加法
        Add add = (a, b) -> a + b;
        
        int result = add.addition(10, 20);
        System.out.println("Sum: " + result);
    }
}

输出:

Sum: 30

Lambda 语法

Lambda 表达式由三部分组成:

  • 参数列表:方法所需的输入参数

  • 箭头符号(->):分隔参数与主体

  • 主体:要执行的逻辑,可以是单个表达式或代码块

通用语法如下:

(parameters) -> expression
或
(parameters) -> { statements; }

函数式接口

函数式接口是指仅包含一个抽象方法的接口。Java 提供了 @FunctionalInterface 注解用于显式声明此类接口(虽非强制,但强烈推荐),以便在编译期检查是否符合规范。

@FunctionalInterface
interface FuncInterface {
    void abstractFun(int x);
    
    // 默认方法不影响“函数式”性质
    default void normalFun() {
        System.out.println("Hello");
    }
}

public class Main {
    public static void main(String[] args) {
        FuncInterface fobj = (int x) -> System.out.println(2 * x);
        fobj.abstractFun(5); // 输出:10
    }
}

Lambda 参数类型

根据参数数量不同,Lambda 表达式可分为以下三类:

1. 无参

@FunctionalInterface
interface ZeroParameter {
    void display();
}

public class Main {
    public static void main(String[] args) {
        ZeroParameter lambda = () -> 
            System.out.println("This is a zero-parameter lambda expression!");
        lambda.display();
    }
}

输出:

This is a zero-parameter lambda expression!

语法:() -> 表达式


2. 单参数

当只有一个参数且类型可推断时,括号可省略。

import java.util.ArrayList;

public class Main {
    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(2);
        list.add(3);

        System.out.println("All elements:");
        list.forEach(n -> System.out.println(n));

        System.out.println("Even elements:");
        list.forEach(n -> {
            if (n % 2 == 0)
                System.out.println(n);
        });
    }
}

输出:

All elements:
1
2
3
Even elements:
2

注意:forEach() 内部使用的是 Consumer<T> 函数式接口,接受一个参数并执行操作,无返回值。


3. 多参数

@FunctionalInterface
interface Functional {
    int operation(int a, int b);
}

public class Main {
    public static void main(String[] args) {
        Functional add = (a, b) -> a + b;
        Functional multiply = (a, b) -> a * b;

        System.out.println(add.operation(6, 3));     // 9
        System.out.println(multiply.operation(4, 5)); // 20
    }
}

语法:(p1, p2, ...) -> 表达式


集合与流中的应用

Lambda 表达式极大简化了对集合的操作,尤其在配合 Stream API 时表现突出。

import java.util.Arrays;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "Adam");

        System.out.println("All names:");
        names.forEach(name -> System.out.println(name));

        System.out.println("\nNames starting with 'A':");
        names.stream()
            .filter(n -> n.startsWith("A"))      // 过滤
            .map(n -> n.toUpperCase())           // 转换
            .forEach(System.out::println);       // 输出
    }
}

输出:

All names:
Alice
Bob
Charlie
Adam

Names starting with 'A':
ALICE
ADAM

此处:

  • filter 使用 Predicate<String>

  • map 使用 Function<String, String>

  • forEach 使用 Consumer<String>


为什么要使用 Lambda

  • 代码更简洁:相比匿名内部类,大幅减少样板代码

  • 支持函数式编程:将行为作为参数传递,提升抽象能力

  • 提高可读性:逻辑集中,意图清晰

  • 增强集合处理能力:与 Stream API 结合,轻松实现过滤、映射、归约等操作


常见内置函数式接口

接口

抽象方法

用途

Predicate<T>

boolean test(T t)

判断条件是否成立(如过滤)

Consumer<T>

void accept(T t)

对输入执行操作,无返回值(如打印)

Supplier<T>

T get()

无输入,生成或提供结果(如工厂方法)

Function<T, R>

R apply(T t)

接收一个参数,返回一个结果(如转换)

Comparator<T>

int compare(T o1, T o2)

比较两个对象的大小

Comparable<T>

int compareTo(T o)

定义对象的自然排序

注意:Comparable 是普通接口,但常与 Lambda 配合使用(如 Collections.sort(list, (a, b) -> a.compareTo(b)))。


重点总结

  • Lambda 表达式是 Java 实现函数式编程的核心工具

  • 必须与函数式接口配合使用(仅含一个抽象方法)

  • 支持零参、单参、多参形式,参数类型通常可自动推断

  • 广泛应用于集合遍历、Stream 流处理、事件回调等场景

  • 内置函数式接口(如 PredicateConsumer)极大提升了开发效率

  • 编写时需注意语法细节,尤其是类型推断和语句完整性


思考题

  1. 为什么 Lambda 表达式不能用于包含多个抽象方法的接口?请结合函数式接口的定义说明。

  2. 在以下代码中,能否将 (n) -> System.out.println(n) 简化为 n -> System.out.println(n)?为什么?

    list.forEach((n) -> System.out.println(n));
  3. 尝试使用 Lambda 表达式和 Stream API 实现:从一个整数列表中筛选出大于 10 的偶数,并将其平方后求和。