三者核心作用是简化函数式接口(仅 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 的进一步简化(引用已有方法)

六、总结

三者是 **“从写全部→写核心→引现成”** 的演进:

  1. 匿名内部类:“我来完整实现接口”(兼容旧版本,冗余);
  2. Lambda 表达式:“我只写核心逻辑”(简化代码,聚焦任务);
  3. 方法引用:“逻辑早有了,直接用”(极致简洁,复用现有方法)。

实际开发中,优先用方法引用(能引用则用),其次 Lambda(逻辑简单),最后匿名内部类(兼容旧代码或特殊场景)。

更多推荐