Java Lambda 表达式详解文档

一、Lambda 表达式概述

Lambda 表达式是 Java 8 引入的核心特性,本质是匿名函数 (无名称的方法),用于简化函数式接口(仅含一个抽象方法的接口)的实现,让代码更简洁、支持函数式编程风格。

核心优势

  1. 代码简洁 :消除匿名内部类的冗余代码(如new@Override)。
  2. 函数作为参数:可将代码块作为方法参数传递,灵活处理数据流(如 Stream API)。
  3. 性能优化 :避免为每个匿名内部类生成独立.class文件,减少内存开销。

二、函数式接口(Lambda 的基石)

Lambda 表达式必须依赖函数式接口 ,即有且仅有一个抽象方法的接口。

1. 定义与注解

  • @FunctionalInterface注解标记(非强制,编译校验)。
  • 接口中只能有一个抽象方法,可包含默认方法、静态方法。
java 复制代码
// 自定义函数式接口
@FunctionalInterface
interface Calculator {
    int compute(int a, int b); // 唯一抽象方法
}

2. JDK 内置四大核心函数式接口(java.util.function包)

表格

接口 抽象方法 用途
Consumer<T> void accept(T t) 消费型:接收参数,无返回值
Supplier<T> T get() 供给型:无参数,返回数据
Predicate<T> boolean test(T t) 断言型:判断条件,返回布尔值
Function<T,R> R apply(T t) 函数型:接收参数,返回结果

三、Lambda 表达式语法

1. 基本结构

java

运行

java 复制代码
(参数列表) -> { 方法体 }
  • 参数列表:对应函数式接口抽象方法的参数,类型可省略(编译器自动推断)。
  • ->:Lambda 操作符,分隔参数与方法体。
  • 方法体 :实现逻辑,单行可省略{}return,多行必须包裹{}并显式return

2. 语法简化规则(必背)

表格

场景 示例 说明
无参数 () -> System.out.println("Hello") 必须写空括号
单个参数 x -> x * 2 可省略括号与参数类型
多个参数 (a, b) -> a + b 不可省略括号,类型可省略
单行方法体 (a, b) -> a + b 省略{}return、分号
多行方法体 x -> { int r = x * 2; return r; } 必须加{},有返回值需return
显式类型 (int a, int b) -> a + b 手动声明参数类型(可选)

四、基础示例

1. 无参数无返回值(Runnable)

java 复制代码
// 传统匿名内部类
Runnable runnable1 = new Runnable() {
    @Override
    public void run() {
        System.out.println("Hello Lambda");
    }
};

// Lambda 简化
Runnable runnable2 = () -> System.out.println("Hello Lambda");
runnable2.run(); // 输出:Hello Lambda

2. 单个参数无返回值(Consumer)

java 复制代码
// 传统写法
Consumer<String> consumer1 = new Consumer<String>() {
    @Override
    public void accept(String s) {
        System.out.println(s);
    }
};

// Lambda 简化
Consumer<String> consumer2 = s -> System.out.println(s);
consumer2.accept("Hello Consumer"); // 输出:Hello Consumer

3. 多个参数有返回值(自定义接口)

java 复制代码
// 自定义函数式接口
@FunctionalInterface
interface MathOp {
    int calculate(int a, int b);
}

// Lambda 实现
MathOp add = (a, b) -> a + b;
MathOp multiply = (a, b) -> a * b;

System.out.println(add.calculate(3, 5)); // 输出:8
System.out.println(multiply.calculate(3, 5)); // 输出:15

4. 断言型接口(Predicate)

java 复制代码
// 判断字符串是否为空
Predicate<String> isEmpty = s -> s == null || s.trim().isEmpty();
System.out.println(isEmpty.test("")); // 输出:true
System.out.println(isEmpty.test("Java")); // 输出:false

5. 函数型接口(Function)

java 复制代码
// 字符串转整数
Function<String, Integer> strToInt = s -> Integer.parseInt(s);
System.out.println(strToInt.apply("123")); // 输出:123

五、Lambda 变量作用域

1. 访问外部变量

Lambda 可访问 ** 外部 final 或 effectively final(无二次赋值)** 的局部变量、成员变量、静态变量。

java 复制代码
int num = 10; // effectively final(未二次赋值)
Runnable runnable = () -> System.out.println(num); // 合法
runnable.run(); // 输出:10

2. 禁止修改外部变量

Lambda 内部不能修改外部局部变量(编译报错)。

复制代码
int count = 0;
Runnable runnable = () -> {
    count++; // 编译错误:Lambda 内部不能修改外部局部变量
};

3. 访问成员变量与静态变量

复制代码
public class LambdaDemo {
    private String msg = "Hello"; // 成员变量
    private static String staticMsg = "Static Hello"; // 静态变量

    public void test() {
        Runnable runnable = () -> {
            System.out.println(msg); // 访问成员变量
            System.out.println(staticMsg); // 访问静态变量
        };
        runnable.run();
    }
}

六、方法引用(Lambda 进阶简化)

方法引用是 Lambda 的简写形式 ,通过::符号直接引用已有方法(静态方法、实例方法、构造方法),进一步简化代码。

1. 静态方法引用:类名::静态方法

复制代码
// Lambda 写法
Function<String, Integer> strToInt1 = s -> Integer.parseInt(s);

// 方法引用
Function<String, Integer> strToInt2 = Integer::parseInt;

2. 实例方法引用:对象::实例方法

复制代码
String str = "Hello";
// Lambda 写法
Supplier<Integer> length1 = () -> str.length();

// 方法引用
Supplier<Integer> length2 = str::length;

3. 构造方法引用:类名::new

复制代码
// Lambda 写法
Supplier<List<String>> listSupplier1 = () -> new ArrayList<>();

// 方法引用
Supplier<List<String>> listSupplier2 = ArrayList::new;

七、Lambda 与 Stream API 结合(核心应用场景)

Stream API 是 Java 8 处理集合数据的工具,大量依赖 Lambda 表达式实现过滤、映射、遍历等操作。

示例:集合过滤、转换、遍历

复制代码
List<String> list = Arrays.asList("Java", "Python", "C++", "JavaScript");

// 1. 过滤(Predicate):筛选以 "J" 开头的字符串
// 2. 转换(Function):转小写
// 3. 遍历(Consumer):打印结果
list.stream()
    .filter(s -> s.startsWith("J"))
    .map(s -> s.toLowerCase())
    .forEach(s -> System.out.println(s));

// 输出:java、javascript

八、Lambda 与匿名内部类对比

表格

对比维度 匿名内部类 Lambda 表达式
本质 真实类对象,生成独立.class文件 无类结构,JVM 动态生成,轻量级
使用范围 可继承类、实现任意接口 仅支持函数式接口
变量访问 可访问外部 final 变量,可修改成员变量 仅访问 final/effectively final 变量
this含义 指向匿名内部类自身 指向外部类对象
代码简洁度 冗余(需重写方法) 极简(省略模板代码)

九、注意事项与常见问题

  1. 必须依赖函数式接口:Lambda 不能独立使用,必须实现函数式接口。
  2. 参数类型推断:编译器可自动推断参数类型,无需手动声明(特殊场景除外)。
  3. 多行方法体需{}return:单行可省略,多行必须规范书写。
  4. 变量作用域限制:不能修改外部局部变量,仅访问 final/effectively final 变量。
  5. 空指针风险:Lambda 中使用外部对象时,需判空避免空指针。

十、总结

Lambda 表达式是 Java 8 函数式编程的核心,通过简洁语法简化函数式接口实现,结合 Stream API 可高效处理集合数据,大幅提升代码简洁性与可读性。掌握 Lambda 需重点理解函数式接口、语法简化规则、变量作用域、方法引用四大核心点。

相关推荐
csbysj20201 小时前
CSS 网格元素
开发语言
lly2024061 小时前
DOM 元素:深入理解与高效运用
开发语言
longxibo1 小时前
【第1章 环境搭建与项目结构解析】
java·后端·流程图
鸟儿不吃草1 小时前
安卓实现左右布局聊天界面
android·开发语言·python
a***72891 小时前
Java进阶(ElasticSearch的安装与使用)
java·elasticsearch·jenkins
Java成神之路-1 小时前
面试题:Spring AOP底层实现原理
java·spring aop
Python私教1 小时前
如意Agent日志系统重构:从 print() 大海捞针到结构化可观测性栈
java·前端·重构
jieyucx2 小时前
Go 零基础数据结构:顺序表(像「排抽屉」一样学增删改查)
java·数据结构·golang
曦夜日长2 小时前
C++ STL容器string(一):string的变量细节、默认函数的认识以及常用接口的使用
java·开发语言·c++