Lambda表达式与匿名内部类的深度理解

一、Lambda 是什么
Lambda就是:简化写法的匿名内部类
作用:不用写多余类名、方法名,只保留「参数 + 逻辑」
专门用来简化函数式接口的代码。

二、核心语法公式
(参数列表) -> { 方法体逻辑 }
拆解:

  • ():放方法参数,无参就空括号
  • ->:Lambda 箭头,固定写法
  • {}:业务代码逻辑

三、前置关键:函数式接口
只要接口里只有一个抽象方法,就是函数式接口
可以用 @FunctionalInterface 标注。
示例:

@FunctionalInterface
interface MyFunc {
    void sayHello();  //只有方法声明,没有{}方法体
}

interface是定义接口的关节字,类比Java中的类class
接口是一套「行为规范、规则清单」,只定义方法声明,不写具体实现。
实现这个接口,必须重写这个方法,自己写具体逻辑。
Lambda 表达式 只能用在接口上,而且这个接口只能有一个抽象方法,叫函数式接口。

四、从传统写法 → Lambda 对比
1. 传统匿名内部类写法

MyFunc f = new MyFunc() {
    @Override
    public void sayHello() {
        System.out.println("Hello 传统写法");
    }
};
f.sayHello();

匿名内部类:(需要用到接口中的方法并且只需要使用一次时,专门定义一个类去实现接口过于麻烦,这个时候就用匿名内部类),直接:
接口名 变量 = new 接口名{重写接口中的方法}
这样就不用单独写一个 class 类名 implements 接口,

原地直接 new 接口,当场重写接口里的抽象方法,(接口里的抽象方法必须全部重写)
适合只用一次、不想单独建一个类的场景。
省去定义实现类,原地创建、原地重写。

不是只需要重写一个方法,而是接口里的方法都要重写

  • 接口有2 个、3 个抽象方法,匿名内部类也能用
  • 只是如果只有 1 个抽象方法(函数式接口),后面可以进一步改成 Lambda

Lambda 简化后

MyFunc f = () -> System.out.println("Hello Lambda");
f.sayHello();

五、带参数、返回值的Lambda写法
1. 一个参数

@FunctionalInterface
interface Calc {
    int add(int a);
}

// Lambda
Calc c = a -> a * 2;
System.out.println(c.add(5)); // 10

2. 多个参数+方法体多行

@FunctionalInterface
interface Calc2 {
    int add(int a, int b);
}

Calc2 c2 = (a,b) -> {
    int sum = a + b;
    return sum;
};
System.out.println(c2.add(3,4)); // 7

六、Lambda省略规则
1. 参数只有一个:可以省略 ()
a -> System.out.println(a)
2. 方法体只有一行:可以省略{}和return
(a,b) -> a + b
3. 参数类型:可全部省略,编译器自动推断
4. 无参数:必须保留空括号 ()

七、开发最常用场景:集合遍历
普通 for 循环

List<String> list = Arrays.asList("张三","李四");
for (String s : list) {
    System.out.println(s);
}

Lambda 简化遍历
list.forEach(s -> System.out.println(s));

八、你要记住的核心结论

  1. Lambda 只能用在函数式接口上(接口只有一个抽象方法)
  2. 本质:简化匿名内部类,去掉冗余模板代码
  3. 格式:(参数) -> 逻辑
  4. 日常最多用:集合遍历、Stream 流、线程启动、Comparator 排序

接口和抽象类的区别
1. 关键字

  • 抽象类:abstract class
  • 接口:interface
    2. 构造方法
  • 抽象类:有构造方法(可以被子类调用)
  • 接口:没有构造方法
    3. 成员变量
  • 抽象类:可以有普通变量、常量
  • 接口:只能是常量(默认 public static final)
    4. 普通方法
  • 抽象类:可以有普通有体方法 + 抽象无体方法
  • 接口:JDK8 之前只能抽象方法;JDK8 后可以有默认方法、静态方法
    5. 继承 / 实现关系
  • 抽象类:单继承 extends 只能继承一个
  • 接口:多实现 implements 可以同时实现多个接口
    6. 设计思想
  • 抽象类:is-a 是什么(学生是人、动物是生物)
  • 接口:has-a / 具备某种能力(会跑、会飞、会排序)
  1. 普通接口多个抽象方法 → 匿名内部类 必须全重写(Java 接口里的抽象方法,默认自带 public abstract,你不写,编译器也会自动帮你补上。)
  2. 不想重写没用的方法 → 要么改成函数式接口,要么给其他方法加 default 默认实现
  3. Lambda 只能用在只有一个抽象方法的接口,就是为了避开 “要重写一堆没用方法” 的麻烦。

代码解释

List<String> list = List.of("张三","李四","王五");

// 挨个取出每个元素 s,打印
list.forEach(s -> System.out.println(s));

forEach = for each
翻译:对每一个、遍历每一个
就是:把集合里每一个元素,挨个拿出来执行一遍操作

forEach 是 Java 集合 List/Set 自带的遍历方法
底层就是帮你封装好了循环,不用你手写 for 循环。
forEach 就是简化版增强 for 循环。

结合刚学的 Lambda / 匿名内部类
forEach 方法接收一个函数式接口 Consumer
所以可以传:

  • 匿名内部类
  • Lambda 表达式

老式匿名内部类写法

list.forEach(new Consumer<String>() {
    @Override
    public void accept(String s) {
        System.out.println(s);
    }
});

简化成 Lambda:
list.forEach(s -> System.out.println(s));

posted @ 2026-05-11 17:07  ZealousMclaren  阅读(18)  评论(0)    收藏  举报