匿名内部类、Lambda 表达式、方法引用 总结(基于函数式接口)
·
三者核心作用是简化函数式接口(仅 1 个抽象方法)的实现,语法从冗余到极简递进,本质都是为了更高效地定义 “代码片段(任务)”。
一、核心前提:函数式接口
必须基于仅含一个抽象方法的接口(可加
@FunctionalInterface注解显式声明),比如:
Runnable(无参无返回):void run()Comparator<T>(双参有返回):int compare(T o1, T o2)Consumer<T>(单参无返回):void accept(T t)Supplier<T>(无参有返回):T get()
二、三者递进实现(以 2 个典型场景为例)
场景 1:排序(用Comparator<Integer>实现整数升序)
1. 匿名内部类(完整但冗余)
需显式new接口、重写方法,语法冗余但兼容性强(Java 8 前唯一方案)。
import java.util.Comparator;
public class Demo {
public static void main(String[] args) {
// 匿名内部类:完整实现Comparator接口
Comparator<Integer> comparator1 = new Comparator<Integer>() {
// 必须重写唯一抽象方法compare
@Override
public int compare(Integer a, Integer b) {
return a - b; // 核心逻辑:升序排序
}
};
// 测试:比较3和5,返回-2(符合升序)
System.out.println(comparator1.compare(3, 5)); // 输出:-2
}
}
2. Lambda 表达式(简化核心逻辑)
省略接口名、new、@Override,仅保留 “参数 + 核心逻辑”,语法更简洁(Java 8+)。
import java.util.Comparator;
public class Demo {
public static void main(String[] args) {
// Lambda简化1:保留参数类型(可省略,编译器自动推断)
Comparator<Integer> comparator2 = (Integer a, Integer b) -> {
return a - b; // 核心逻辑不变
};
// Lambda简化2:省略参数类型、大括号、return(单行逻辑可省)
Comparator<Integer> comparator3 = (a, b) -> a - b; // 最简形式
// 测试:结果与匿名内部类一致
System.out.println(comparator3.compare(3, 5)); // 输出:-2
}
}
3. 方法引用(引用现成方法,极致简洁)
若核心逻辑已在某个现成方法中实现(方法签名与接口抽象方法匹配),直接引用该方法,无需重复写逻辑。
import java.util.Comparator;
public class Demo {
public static void main(String[] args) {
// 方法引用:Integer类的静态方法compare(int x, int y)
// 其签名(双int参数、返回int)与Comparator.compare完全匹配
Comparator<Integer> comparator4 = Integer::compare;
// 测试:结果完全一致,无需写任何逻辑
System.out.println(comparator4.compare(3, 5)); // 输出:-2
}
}
场景 2:执行任务(用Runnable实现打印)
1. 匿名内部类
Runnable runnable1 = new Runnable() {
@Override
public void run() {
System.out.println("执行任务1"); // 核心逻辑
}
};
new Thread(runnable1).start(); // 启动线程
2. Lambda 表达式
// 最简形式:无参(空括号)、单行逻辑省大括号
Runnable runnable2 = () -> System.out.println("执行任务2");
new Thread(runnable2).start();
3. 方法引用(引用自定义静态方法)
// 1. 先定义现成的静态方法(与Runnable.run()签名匹配:无参无返回)
public static void printTask() {
System.out.println("执行任务3");
}
// 2. 引用该静态方法
Runnable runnable3 = Demo::printTask;
new Thread(runnable3).start();
三、格式总结表(按参数场景分类)
| 方法类型 | 参数场景 | 通用格式 |
|---|---|---|
| 匿名内部类 | 无参无返回(如 Runnable) | 接口名 变量名 = new 接口名 () {@Overridepublic 返回值 方法名 () { 逻辑}}; |
| 单参无返回(如 Consumer) | 接口名 <类型> 变量名 = new 接口名 < 类型 >() {@Overridepublic void 方法名 (类型 参数) { 逻辑 }}; | |
| 双参有返回(如 Comparator) | 接口名 <类型> 变量名 = new 接口名 < 类型 >() {@Overridepublic 返回值 方法名 (类型 1 参数 1, 类型 2 参数 2) { 逻辑 }}; | |
| Lambda 表达式 | 无参无返回 | 接口名 变量名 = () -> { 逻辑 }(单行逻辑可省:() -> 逻辑) |
| 单参无返回 | 接口名 <类型> 变量名 = (参数) -> { 逻辑 }(简化:参数 -> 逻辑) | |
| 双参有返回 | 接口名 <类型> 变量名 = (参数 1, 参数 2) -> { 逻辑 }(简化:(p1,p2) -> 逻辑) | |
| 方法引用 | 无参无返回(引用静态方法) | 接口名 变量名 = 类名::静态方法名 |
| 单参无返回(引用实例方法) | 接口名 <类型> 变量名 = 对象实例::实例方法名 | |
| 双参有返回(引用静态方法) | 接口名 <类型> 变量名 = 类名::静态方法名(方法需匹配双参 + 返回值) |
四、不同情况实例表(覆盖常用函数式接口)
| 函数式接口 | 匿名内部类实例 | Lambda 实例 | 方法引用实例 |
|---|---|---|---|
| Runnable(无参无返回) | Runnable r = new Runnable() {@Overridepublic void run() {System.out.println ("匿名类执行");}}; | Runnable r = () -> System.out.println ("Lambda 执行"); | // 先定义静态方法:public static void runTask () {System.out.println ("方法引用执行");}Runnable r = Demo::runTask; |
| Consumer<String>(单参无返回) | Consumer<String> c = new Consumer<String>() {@Overridepublic void accept(String s) {System.out.println(s);}}; | Consumer<String> c = s -> System.out.println(s); | // 引用 System.out 的实例方法 printlnConsumer<String> c = System.out::println; |
| Comparator<String>(双参有返回) | Comparator<String> c = new Comparator<String>() {@Overridepublic int compare(String s1, String s2) {return s1.length() - s2.length();}}; | Comparator<String> c = (s1, s2) -> s1.length() - s2.length(); | // 引用 String 的实例方法 length(类名::实例方法)Comparator<String> c = Comparator.comparingInt(String::length); |
| Supplier<Integer>(无参有返回) | Supplier<Integer> s = new Supplier<Integer>() {@Overridepublic Integer get() {return new Random().nextInt(10);}}; | Supplier<Integer> s = () -> new Random().nextInt(10); | // 引用 Random 的实例方法 nextInt(先创建对象)Random random = new Random();Supplier<Integer> s = random::nextInt; |
函数式接口、匿名内部类、Lambda 及方法引用的对应实例
import java.util.Comparator;
import java.util.Random;
import java.util.function.Consumer;
import java.util.function.Supplier;
public class FunctionalInterfaceExamples {
// 用于方法引用的静态方法(Runnable 示例)
public static void runTask() {
System.out.println("方法引用执行");
}
public static void main(String[] args) {
// 1. Runnable(无参无返回)
// 匿名内部类实例
Runnable runnableAnon = new Runnable() {
@Override
public void run() {
System.out.println("匿名类执行");
}
};
// Lambda 实例
Runnable runnableLambda = () -> System.out.println("Lambda 执行");
// 方法引用实例(引用静态方法)
Runnable runnableMethodRef = FunctionalInterfaceExamples::runTask;
// 2. Consumer<String>(单参无返回)
// 匿名内部类实例
Consumer<String> consumerAnon = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
// Lambda 实例
Consumer<String> consumerLambda = s -> System.out.println(s);
// 方法引用实例(引用实例方法)
Consumer<String> consumerMethodRef = System.out::println;
// 3. Comparator<String>(双参有返回)
// 匿名内部类实例
Comparator<String> comparatorAnon = new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return s1.length() - s2.length();
}
};
// Lambda 实例
Comparator<String> comparatorLambda = (s1, s2) -> s1.length() - s2.length();
// 方法引用实例(引用类的实例方法)
Comparator<String> comparatorMethodRef = Comparator.comparingInt(String::length);
// 4. Supplier<Integer>(无参有返回)
// 匿名内部类实例
Supplier<Integer> supplierAnon = new Supplier<Integer>() {
@Override
public Integer get() {
return new Random().nextInt(10);
}
};
// Lambda 实例
Supplier<Integer> supplierLambda = () -> new Random().nextInt(10);
// 方法引用实例(引用对象的实例方法)
Random random = new Random();
Supplier<Integer> supplierMethodRef = random::nextInt;
}
}
五、三者核心差异对比表
| 特性 | 匿名内部类 | Lambda 表达式 | 方法引用 |
|---|---|---|---|
| 语法冗余度 | 最高(需写接口、重写方法) | 中等(仅保留参数 + 逻辑) | 最低(仅引用现成方法) |
| 核心依赖 | 函数式接口 | 函数式接口 | 函数式接口 + 现成匹配方法 |
| 适用场景 | Java 8 前;需访问外部变量(非 final 也可,编译器隐式 final) | Java 8+;逻辑简单直接 | Java 8+;逻辑已在现成方法中实现 |
| 本质 | 匿名子类实例 | 函数式接口的匿名实现(编译后仍是匿名类) | Lambda 的进一步简化(引用已有方法) |
六、总结
三者是 **“从写全部→写核心→引现成”** 的演进:
- 匿名内部类:“我来完整实现接口”(兼容旧版本,冗余);
- Lambda 表达式:“我只写核心逻辑”(简化代码,聚焦任务);
- 方法引用:“逻辑早有了,直接用”(极致简洁,复用现有方法)。
实际开发中,优先用方法引用(能引用则用),其次 Lambda(逻辑简单),最后匿名内部类(兼容旧代码或特殊场景)。
更多推荐

所有评论(0)