Wrayの知识库 Wrayの知识库
首页
  • Java 基础
  • Java 集合
  • Java 并发
  • Java IO
  • JVM
  • Spring Framework
  • Spring Boot
  • Spring Cloud
  • Spring Security
  • MySQL
  • Redis
  • 计算机基础
  • 操作系统原理
  • Linux
  • MacOS
  • Windows
  • 系统工程与研究专题
  • AI 基础
  • 大模型基础
  • Prompt 工程
  • RAG 检索增强生成
  • Agent 智能体
  • AI 应用开发
  • AI 工程化
  • AI 安全与治理
  • AI 面试与设计题
  • 纸质书
  • 电子书
  • 学习课程
疑难杂症
GitHub (opens new window)
首页
  • Java 基础
  • Java 集合
  • Java 并发
  • Java IO
  • JVM
  • Spring Framework
  • Spring Boot
  • Spring Cloud
  • Spring Security
  • MySQL
  • Redis
  • 计算机基础
  • 操作系统原理
  • Linux
  • MacOS
  • Windows
  • 系统工程与研究专题
  • AI 基础
  • 大模型基础
  • Prompt 工程
  • RAG 检索增强生成
  • Agent 智能体
  • AI 应用开发
  • AI 工程化
  • AI 安全与治理
  • AI 面试与设计题
  • 纸质书
  • 电子书
  • 学习课程
疑难杂症
GitHub (opens new window)
  • Java章节编写规范
  • Java基础

    • Java概述
    • Java语法
    • 面向对象编程
    • Java数组
    • String字符串
    • 异常处理
    • 基本类型与包装类
    • Object类与常用方法
    • 泛型
    • 枚举与注解
    • 反射
    • 值传递与引用
    • Lambda表达式与函数式接口
      • 1. 从匿名内部类到 Lambda
      • 2. 函数式接口
      • 3. 常用函数式接口
      • 4. Lambda 语法
      • 5. 方法引用
      • 6. 变量捕获
      • 7. Lambda 与 this
      • 8. 常见场景
      • 9. 使用边界
      • 10. 底层机制与工程取舍
      • Tips 快问快答
    • Stream API
    • Optional与空值处理
    • 日期时间API
    • Java现代语法特性
  • Java集合

  • Java并发

  • Java IO

  • JVM

目录

Lambda表达式与函数式接口

Lambda 表达式是 Java 8 引入的重要语法,用于把“行为”作为值传递。它让匿名内部类变得更简洁,也为 Stream、CompletableFuture、集合排序等 API 提供了基础。

学习 Lambda 不要只看语法糖,更要理解函数式接口、变量捕获、方法引用和工程边界。

# 1. 从匿名内部类到 Lambda

匿名内部类:

Runnable task = new Runnable() {
    @Override
    public void run() {
        System.out.println("run");
    }
};

Lambda:

Runnable task = () -> System.out.println("run");

本质上,Lambda 是对函数式接口实例的简洁表达。

# 2. 函数式接口

函数式接口是只有一个抽象方法的接口。

@FunctionalInterface
public interface Converter<T, R> {
    R convert(T value);
}

使用:

Converter<String, Integer> converter = value -> Integer.parseInt(value);

@FunctionalInterface 不是必须的,但推荐添加,让编译器帮你检查接口是否仍然只有一个抽象方法。

# 3. 常用函数式接口

接口 抽象方法 含义
Runnable run() 无入参无返回
Supplier<T> get() 提供一个值
Consumer<T> accept(T) 消费一个值
Function<T,R> apply(T) 输入 T 输出 R
Predicate<T> test(T) 判断条件
BiFunction<T,U,R> apply(T,U) 两个输入一个输出

示例:

Predicate<User> activeUser = User::isActive;
Function<User, String> nameMapper = User::getName;
Consumer<User> printer = user -> System.out.println(user.getName());
Supplier<List<User>> supplier = ArrayList::new;

# 4. Lambda 语法

() -> expression
value -> expression
(a, b) -> expression
(a, b) -> {
    statement;
    return result;
}

示例:

Comparator<User> byAge = (u1, u2) -> Integer.compare(u1.getAge(), u2.getAge());

如果只有一个参数,可以省略括号:

user -> user.getName()

如果方法体只有一个表达式,可以省略 return 和大括号。

# 5. 方法引用

方法引用是 Lambda 的进一步简化。

形式 示例
静态方法 Integer::parseInt
实例方法 user::getName
类的实例方法 User::getName
构造方法 ArrayList::new

等价关系:

Function<String, Integer> f1 = value -> Integer.parseInt(value);
Function<String, Integer> f2 = Integer::parseInt;

方法引用不是新能力,只是更简洁的写法。

# 6. 变量捕获

Lambda 可以访问外部局部变量,但变量必须是 final 或 effectively final。

String prefix = "user:";
Function<Long, String> mapper = id -> prefix + id;

不能这样:

String prefix = "user:";
prefix = "order:";
Function<Long, String> mapper = id -> prefix + id; // 编译失败

原因是 Lambda 可能在稍后执行,如果外部局部变量随意变化,会破坏语义清晰性。

# 7. Lambda 与 this

匿名内部类中的 this 指向匿名内部类对象;Lambda 中的 this 指向外部对象。

public class Demo {
    public void test() {
        Runnable task = () -> System.out.println(this.getClass());
    }
}

这点在重构匿名内部类为 Lambda 时需要注意。

# 8. 常见场景

集合排序:

users.sort(Comparator.comparing(User::getAge));

过滤:

List<User> activeUsers = users.stream()
        .filter(User::isActive)
        .toList();

异步任务:

CompletableFuture.supplyAsync(() -> queryUser(userId), executor);

回调:

button.onClick(event -> submit());

# 9. 使用边界

Lambda 适合短小、语义明确的行为表达。

不推荐:

users.forEach(user -> {
    validate(user);
    remoteCall(user);
    updateDatabase(user);
    writeAuditLog(user);
});

复杂业务逻辑应抽成具名方法:

users.forEach(this::processUser);

# 10. 底层机制与工程取舍

Lambda 在源码层面像是“匿名函数”,但 Java 没有直接把函数变成一等公民。编译器会根据目标类型进行类型推断,把 Lambda 绑定到某个函数式接口上。

Lambda 表达式
  │ 编译期目标类型推断
  ▼
函数式接口
  │ invokedynamic / LambdaMetafactory
  ▼
运行期生成或复用接口实例

从工程角度看,Lambda 的价值是降低样板代码,但它也会隐藏调用栈和业务语义。过长的 Lambda、带副作用的 Lambda、在 Stream 中做远程调用,都会让排查变难。

场景 推荐 原因
排序、过滤、映射 Lambda 或方法引用 行为短小清晰
复杂业务流程 具名方法 可读性、复用、日志更好
需要异常上下文 具名方法或显式 try/catch Lambda 中异常定位弱
公共策略扩展 函数式接口 比匿名类更轻量
有状态逻辑 谨慎 容易引入共享状态和并发问题

设计函数式接口时要注意接口语义,而不是只看参数和返回值。例如 Predicate<User> 能表达判断,但 UserMatcher 这种具名接口在复杂领域规则中可能更清楚。

# Tips 快问快答

Q:Lambda 是什么? A:Lambda 是函数式接口实例的简洁写法,用于传递行为。

Q:什么是函数式接口? A:只有一个抽象方法的接口。

Q:@FunctionalInterface 必须写吗? A:不是必须,但推荐写,便于编译器检查。

Q:Lambda 能访问外部变量吗? A:能,但局部变量必须是 final 或 effectively final。

Q:方法引用和 Lambda 有什么关系? A:方法引用是某些 Lambda 的简化写法。

Q:Lambda 中的 this 指向谁? A:指向外部对象,不是 Lambda 自身。

Q:Lambda 会让代码一定更好吗? A:不一定。逻辑复杂时具名方法更清晰。

Q:Lambda 和 Stream 是一回事吗? A:不是。Stream 常使用 Lambda 表达处理逻辑。

上次更新: 2026/06/25, 14:19:18
值传递与引用
Stream API

← 值传递与引用 Stream API→

Copyright © 2023-2026 Wray | 鄂ICP备2024050235号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式