Lambda 表达式是 Java 8 引入的重要特性,它是一种匿名函数,可以作为方法参数传递或赋值给变量。Lambda 表达式让代码更加简洁,特别适用于函数式编程场景。

1. 基本语法

(parameters) -> expression
// 或
(parameters) -> { statements; }
  • parameters: 参数列表(可以省略类型)
  • ->: Lambda 操作符
  • expression/statements: 函数体(简单表达式可以省略花括号)

2. 核心概念:函数式接口

java Lambda 表达式只能用于函数式接口(Functional Interface):

  • 只包含一个抽象方法的接口
  • 可以使用 @FunctionalInterface 注解标记

常见的函数式接口:

接口 抽象方法 用途
Function<T,R> R apply(T t) 输入T,输出R
Consumer<T> void accept(T t) 消费T,无返回值
Supplier<T> T get() 无输入,返回T
Predicate<T> boolean test(T t) 判断T是否满足条件
Runnable void run() 无参数无返回值

这些接口为什么叫"函数式"接口?因为这些接口本质上就代表一个函数

  • 输入:参数列表
  • 输出:返回值
  • 功能:方法体要做的事情

Lambda 表达式让我们可以直接写出这个"函数",而不需要包装在类和方法中:

  • Lambda 表达式 = 函数式接口中抽象方法的实现
  • 编译器会自动将 Lambda 表达式转换为对应的函数式接口实例

3. 常见用法示例

3.1. 替代匿名内部类

传统方式(匿名内部类):

// 创建一个 Consumer 接口的实现
Consumer<String> printer = new Consumer<String>() {
    @Override
    public void accept(String message) {
        System.out.println(message);
    }
};

printer.accept("Hello"); // 输出: Hello

Lambda 表达式方式:

// 同样的功能,但代码简洁多了
Consumer<String> printer = (String message) -> {
    System.out.println(message);
};

// 还可以进一步简化(编译器能推断出类型,所以可以省略输入参数类型String)
Consumer<String> printer2 = message -> System.out.println(message);

printer2.accept("Hello"); // 输出: Hello

3.2. 集合操作 - forEach

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");

// 传统 for 循环
for (String name : names) {
    System.out.println(name);
}

// Lambda + forEach
names.forEach(name -> System.out.println(name));

// 方法引用(更简洁)
names.forEach(System.out::println);

3.3. Stream API 过滤和转换

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

// 过滤偶数并平方
List<Integer> result = numbers.stream()
    .filter(n -> n % 2 == 0)        // Predicate
    .map(n -> n * n)                // Function
    .collect(Collectors.toList());

System.out.println(result); // [4, 16, 36, 64, 100]

3.4. 自定义函数式接口

@FunctionalInterface
interface Calculator {
    int calculate(int a, int b);
}

public class Main {
    public static void main(String[] args) {
        Calculator add = (a, b) -> a + b;
        Calculator multiply = (a, b) -> a * b;
        
        System.out.println(add.calculate(5, 3));      // 8
        System.out.println(multiply.calculate(5, 3)); // 15
    }
}

3.5. 带参数的 Lambda

// 无参数: Supplier 接口:无参数,有返回值
Supplier<String> greeting = () -> "Hello, Lambda!";
System.out.println(supplier.get()); // Hello Lambda


// 单个参数:Consumer 接口:一个参数,无返回值
Consumer<String> consumer = (str) -> System.out.println(str);
// 或者省略括号
Consumer<String> consumer2 = str -> System.out.println(str);


// 多个参数:BiFunction 接口:两个参数,有返回值
BiFunction<Integer, Integer, Integer> adder = (a, b) -> a + b;
System.out.println(adder.apply(3, 5)); // 8

3.6. 多行 Lambda 表达式

// 方法体有多行
List<String> words = Arrays.asList("hello", "world", "java");

words.forEach(word -> {
    String upper = word.toUpperCase();
    System.out.println("Original: " + word + ", Upper: " + upper);
});

3.7 简化写法

1. 方法体只有一行,可以省略大括号和 return 关键字

// 方法体只有一行:可以省略大括号和 return 关键字
Function<Integer, Integer> square = x -> x * x;
// 等价于
Function<Integer, Integer> square2 = x -> { return x * x; };

2. 自动类型推断

// 编译器能推断出类型,所以可以省略
Function<String, Integer> parser = s -> Integer.parseInt(s);
// 而不是
Function<String, Integer> parser = (String s) -> Integer.parseInt(s);

3. 方法引用(更简洁)

// Lambda 表达式
Function<String, Integer> parser1 = s -> Integer.parseInt(s);

// 方法引用(等价)
Function<String, Integer> parser2 = Integer::parseInt;

3.8. 实际应用场景

1. 事件处理:

button.addActionListener(e -> System.out.println("Button clicked!"));

2. 排序:

List<Person> people = // ... 初始化数据
people.sort((p1, p2) -> p1.getAge() - p2.getAge());
// 或使用方法引用
people.sort(Comparator.comparing(Person::getAge));

3. 线程创建:

Thread thread = new Thread(() -> {
    // 执行任务
    System.out.println("Running in thread: " + Thread.currentThread().getName());
});
thread.start();

4. Lambda 表达式的变量作用域

Lambda 表达式可以访问外部变量,但有以下限制:

public void scopeExample() {
    final int x = 10;
    int y = 20;
    
    // 可以访问 final 变量
    Runnable r1 = () -> System.out.println(x);
    
    // 可以访问"effectively final"变量(该变量后续不能被修改)
    Runnable r2 = () -> System.out.println(y);
    
    // y = 30; // 如果取消注释,上面的 r2 会编译错误
    
    // 不能修改外部局部变量
    // Runnable r3 = () -> y = 30; // 编译错误
}

5. 总结

优势总结

  1. 代码简洁:减少样板代码
  2. 可读性好:逻辑更清晰
  3. 支持函数式编程:便于并行处理
  4. 提高开发效率:配合 Stream API 强大功能

注意事项

  • Lambda 表达式不是万能的,过度使用可能降低代码可读性
  • 性能方面,首次调用会有一定开销,但后续调用性能良好
  • 调试时堆栈信息可能不如传统方法清晰

6. 相关文档

1.Java常用函数式接口简介: https://blog.csdn.net/taotiezhengfeng/article/details/157020377

2.Collectors.toMap() 用法简介: https://blog.csdn.net/taotiezhengfeng/article/details/156993078

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐