元数据卡
- 前置知识:第5章(方法定义)、第8章(接口)
- 预计时间:20 分钟
- 阅读模式:高度专注
- 完成标志:能写出 Lambda 表达式,理解函数式接口
你的进度
老陈见你继承多态都用利索了,丢给你一个更刁钻的问题。村口需要一套事件报警系统——每次有状况都要执行一串操作,你不想为每种状况都新建一个类。
你现在的做法是每来一个新事件就创建一个新类:
java
class FloodEventHandler implements EventHandler {
@Override
public void handle(Event event) {
notifyVillageChief(event);
logEvent(event);
prepareSandbags(event);
}
}三个事件 → 三个类。五个事件 → 五个类。
老陈师傅摇了摇头:"你就是造打铁炉子的——一锤一锤地敲。知不知道有一种更快的方法,可以把一段行为像包裹一样直接递过去?"
他拿出一片羽毛,在上面写了几行字。"这叫 Lambda。"
你的任务:能不能把"一段行为"当成一个值——像传数字、传字符串一样——直接传过去?
第一幕:函数式接口——Lambda 的插座
Lambda 需要一个"插座"——函数式接口,也就是只有一个抽象方法的接口:
java
@FunctionalInterface // 安全网
public interface EventHandler {
void handle(Event event);
}标准库里的 Runnable、Callable、Comparator——都只有一个抽象方法,等着被 Lambda 插上。
第二幕:Lambda——把行为装进信封
以前怎么用匿名内部类?
java
EventHandler handler = new EventHandler() {
@Override
public void handle(Event event) {
System.out.println("事件发生: " + event.name());
}
};Lambda 把它压缩成一行:
java
EventHandler handler = (event) -> System.out.println("事件发生: " + event.name());语言:Java 8+ 如何运行:
java
public class LambdaDemo {
public static void main(String[] args) {
EventHandler h = (event) -> {
System.out.println("事件: " + event.name());
System.out.println("时间: " + event.time());
};
h.handle(new Event("敌军来袭", 1719123456789L));
processEvent(e -> System.out.println("处理: " + e.name()));
}
static void processEvent(EventHandler h) {
h.handle(new Event("深夜异动", 1719123456790L));
}
}
record Event(String name, long time) {}预期输出:
事件: 敌军来袭
时间: 1719123456789
处理: 深夜异动Lambda 语法拆解:(参数列表) -> { 方法体 }
| 部分 | 说明 | 简化规则 |
|---|---|---|
(event) | 参数 | 单一参数可省略括号 |
-> | Lambda 操作符 | 固定写法 |
{ ... } | 方法体 | 单语句可省花括号和 return |
各种形式:
java
Runnable r = () -> System.out.println("跑起来了"); // 无参
Consumer<String> c = msg -> System.out.println(msg); // 单参
Comparator<Integer> comp = (a, b) -> a - b; // 多参
Comparator<Integer> v = (a, b) -> { // 多行
System.out.println("比较中...");
return a - b;
};第三幕:四大函数式接口
记住 四大天王:
| 接口 | 方法签名 | 用途 | 示意 |
|---|---|---|---|
Supplier<T> | T get() | 生产值 | () -> "hello" |
Consumer<T> | void accept(T) | 消费值 | s -> System.out.println(s) |
Function<T,R> | R apply(T) | 转换值 | s -> s.length() |
Predicate<T> | boolean test(T) | 判断真假 | s -> s.length() > 5 |
真实例子:
java
List<String> msgs = List.of("敌军", "天气", "喜报", "求救");
Predicate<String> isUrgent = msg -> msg.equals("敌军") || msg.equals("求救");
Function<String, String> wrap = msg -> "[消息] " + msg;
msgs.stream().filter(isUrgent).map(wrap).forEach(System.out::println);
Supplier<String> ready = () -> "系统就绪";
System.out.println(ready.get());语言:Java 8+ 预期输出: [消息] 敌军 [消息] 求救 系统就绪
常见陷阱:effectively final
java
String prefix = "[消息]";
EventHandler h = event -> {
prefix = "[紧急] " + prefix; // 编译错误——修改了捕获变量
};用数组包装来解决:
java
String[] prefix = {"[消息]"};
EventHandler h = event -> {
prefix[0] = "[紧急]";
System.out.println(prefix[0] + event.name());
};旅人笔记
Lambda 把行为装进信封传给别人。 函数式接口是插座,Lambda 是插头。 四大天王:Supplier 生产值,Consumer 消费值,Function 转换值,Predicate 判断值。
→ 下一站预告
Lambda 让你有了传递行为的工具。但还需要一个接受它的数据管道——Stream API。