JAVA重点基础、进阶知识及易错点总结(25)Lambda 表达式
·
🚀 Java 巩固进阶 · 第 25 天
主题:Lambda 表达式 —— 函数式编程入门
📅 进度概览:恭喜完成 Java 基础巩固阶段(1-24 天)!从今天起,进入 JDK8+ 新特性阶段。Lambda 是 Java 函数式编程的基石,也是后续学习 Stream 流、Optional 乃至 Spring 函数式接口的 prerequisite。
💡 核心价值:
- 代码简洁:消除匿名内部类的样板代码,让核心逻辑更突出。
- 函数式思维:将“行为”作为参数传递,为集合流式处理打下基础。
- 框架基石:Spring 回调、MyBatis 函数式接口、Java 并发包都大量使用 Lambda。
- 面试高频:函数式接口、方法引用、Lambda 底层原理是必考题。
一、为什么需要 Lambda?告别匿名内部类 🎯
1. 传统写法 vs Lambda 写法
// ❌ 传统:匿名内部类(啰嗦,重点不突出)
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("线程执行了");
}
}).start();
// ✅ Lambda:只关心“做什么”,不关心“类结构”
new Thread(() -> {
System.out.println("线程执行了");
}).start();
2. 本质理解
┌─────────────────────────────────────┐
│ 🔄 Lambda 本质 │
│ 是“匿名函数” + “函数式接口实例” │
│ │
│ 前提:接口必须只有一个抽象方法 │
│ 好处:编译器自动推断类型,代码极简 │
└─────────────────────────────────────┘
💡 一句话理解:
“Lambda 就是简化版的匿名内部类,只保留核心逻辑代码”
二、语法规范与函数式接口 📝
1. Lambda 表达式语法
// 标准格式:(参数列表) -> { 方法体 }
(a, b) -> { return a + b; };
// ✅ 简化规则(编译器自动推断):
// 1. 参数类型可省略
// 2. 单个参数可省略括号
// 3. 单行代码可省略大括号和 return
(a, b) -> a + b; // 最简写法
2. 函数式接口(@FunctionalInterface)
// ✅ 规范:只能有一个抽象方法
@FunctionalInterface
public interface MyCalculator {
int calculate(int a, int b); // 抽象方法
// 可以有默认方法/静态方法,不影响函数式特性
default void print() { System.out.println("计算"); }
}
// ✅ 使用 Lambda 实现
MyCalculator add = (a, b) -> a + b;
System.out.println(add.calculate(3, 5)); // 输出 8
3. JDK 内置四大核心函数式接口(⭐ 必背)
| 接口 | 泛型 | 抽象方法 | 作用 | 示例 |
|---|---|---|---|---|
| Consumer | <T> |
void accept(T t) |
消费型(有参无返) | list.forEach(System.out::println) |
| Supplier | <T> |
T get() |
供给型(无参有返) | () -> new User() |
| Function | <T,R> |
R apply(T t) |
函数型(有参有返) | s -> s.length() |
| Predicate | <T> |
boolean test(T t) |
断言型(判断) | s -> s.isEmpty() |
三、方法引用:Lambda 的极致简化 :: ⚡
1. 什么是方法引用?
🎯 场景:Lambda 体内部只是调用了一个已有方法
✅ 解决:直接用方法名引用,更简洁
2. 四种引用方式
// 1️⃣ 静态方法引用:类名::方法名
Function<String, Integer> parser = Integer::parseInt; // 等价于 s -> Integer.parseInt(s)
// 2️⃣ 实例方法引用:对象::方法名
String str = "hello";
Supplier<Integer> lenProvider = str::length; // 等价于 () -> str.length()
// 3️⃣ 类实例方法引用:类名::方法名(特殊,第一个参数作为调用者)
Function<String, Integer> lenFunc = String::length; // 等价于 s -> s.length()
// 4️⃣ 构造器引用:类名::new
Supplier<User> userSupplier = User::new; // 等价于 () -> new User()
💡 记忆口诀:
“Lambda 体里只调用,方法引用来简化;静态类名实例对象,构造器用 new 替代”
四、🎯 今日实战任务:Lambda 重构练习
任务 1:重写线程创建代码
/**
* 要求:
* 1. 用 Lambda 表达式重写 Runnable 实现
* 2. 用方法引用重写(如果适用)
* 3. 对比代码行数差异
*
* 💡 提示:
* new Thread(() -> System.out.println("Hello"));
*/
任务 2:集合排序重构
/**
* 业务场景:用户列表按年龄排序
*
* 要求:
* 1. 创建 User 类(name, age)
* 2. 传统写法:new Comparator<User>() { ... }
* 3. Lambda 写法:(u1, u2) -> u1.getAge() - u2.getAge()
* 4. 方法引用:Comparator.comparingInt(User::getAge)
*
* 💡 挑战:
* - 尝试按姓名长度排序
* - 尝试链式排序:先按年龄,年龄相同按姓名
*/
List<User> users = Arrays.asList(
new User("Alice", 20),
new User("Bob", 18)
);
// TODO: 用 Lambda 排序
任务 3:自定义函数式接口
/**
* 要求:
* 1. 定义 @FunctionalInterface Operation
* 2. 抽象方法:int compute(int a, int b)
* 3. 创建 Lambda 实现:加法、减法、乘法
* 4. 编写方法 executeOperation(int a, int b, Operation op)
*
* 💡 提示:
* 模拟策略模式,用 Lambda 替代策略类
*/
任务 4:遍历与消费(Consumer)
/**
* 要求:
* 1. 创建 List<String> 包含 5 个名字
* 2. 用 foreach 循环遍历打印
* 3. 用 List.forEach() + Lambda 遍历打印
* 4. 用方法引用 System.out::println 遍历打印
*
* 💡 观察:
* 代码越来越简洁,但可读性是否下降?(思考平衡点)
*/
📝 第 25 天 · 核心总结(极简背诵版)
-
Lambda 本质:
简化版匿名内部类 前提:函数式接口(只有一个抽象方法) -
语法简化规则:
(int a, int b) -> { return a + b; } // 标准 (a, b) -> a + b // 最简 -
四大核心接口:
Consumer<T>:void accept(T) → 消费 Supplier<T>:T get() → 供给 Function<T,R>:R apply(T) → 转换 Predicate<T>:boolean test(T)→ 判断 -
方法引用:
静态方法:Class::method 实例方法:object::method 构造器:Class::new
明天预告:🔥 Stream 流式编程 —— 集合处理的革命!
- Stream 创建(Collection.stream, Stream.of)
- 中间操作(filter, map, sorted, distinct)
- 终止操作(collect, forEach, count)
- 实战:用户数据筛选、转换、统计
准备好了吗?明天我们让集合操作“流”起来! 🌊✨
更多推荐
所有评论(0)