Java 回调机制、Lambda 表达式与匿名内部类,【一文详解】

Java 回调机制、Lambda 表达式与匿名内部类

1. 回调对象与回调方法

在异步编程中,如果使用 Future 获取异步执行结果,要么调用阻塞方法 get(),要么轮询 isDone(),这两种方式都不好,因为主线程会被迫等待。

Java 8 引入的 CompletableFuture 改进了这个问题,可以传入回调对象,当异步任务完成或发生异常时,自动调用回调方法。

✅ 示例代码

import java.util.concurrent.*;

public class CompletableFutureDemo {
    public static void main(String[] args) {
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("异步任务开始...");
            try { Thread.sleep(1000); } catch (InterruptedException e) {}
            return 42;
        });

        // 注册回调方法:任务完成后自动执行
        future.thenAccept(result -> {
            System.out.println("回调方法被调用,结果是:" + result);
        });

        System.out.println("主线程继续执行,不会被阻塞...");
        try { Thread.sleep(2000); } catch (InterruptedException e) {}
    }
}

输出:

异步任务开始...
主线程继续执行,不会被阻塞...
回调方法被调用,结果是:42

🔍 对应概念

  • 回调对象future 这个 CompletableFuture 实例,它会管理任务完成后的通知。
  • 回调方法thenAccept(result -> {...}) 里的 Lambda,这段逻辑在异步任务完成后自动调用。

✅ 为什么比 get()isDone() 好?

  • get():会阻塞主线程直到结果出来。
  • isDone():需要不停轮询,浪费 CPU。
  • 回调方法:完全异步,任务完成时才触发执行,不会阻塞主线程,也不需要轮询。

2. Lambda 表达式 () -> {}

() -> {}Lambda 表达式,Java 8 引入的语法,用于简化匿名类的写法,特别适用于 函数式接口(只有一个抽象方法的接口,如 RunnableCallableComparator 等)。

结构说明

  • ():参数列表(无参数时写 (),一个参数可省略括号,多参数用括号括起来)。
  • ->:Lambda 操作符,读作“goes to”。
  • {}:方法体,可以包含多行代码(单行时可省略 {}return)。

✅ 示例

无参数,无返回值

Runnable task = () -> {
    System.out.println("Task executed");
};
task.run();

一个参数,有返回值

Function<Integer, Integer> square = x -> x * x;
System.out.println(square.apply(5)); // 输出 25

多个参数,有返回值

BiFunction<Integer, Integer, Integer> add = (a, b) -> a + b;
System.out.println(add.apply(3, 7)); // 输出 10

为什么经常出现 () -> {}

很多异步或回调场景(如 CompletableFuture、线程池、事件监听器)需要传入一个函数式接口实例。
以前必须写匿名类,现在用 Lambda 简洁很多:

new Thread(() -> {
    System.out.println("Running in another thread");
}).start();

3. 匿名内部类:new Runnable() { ... }

new Runnable() { ... }匿名内部类(Anonymous Inner Class),用于即时实现一个接口或继承一个类,并创建该类的对象。

为什么要写 {}

因为接口没有方法体,必须提供实现。如果只写 new Runnable(),只是创建了接口引用,没有实现方法,会编译报错。

✅ 完整例子

Runnable r = new Runnable() {
    @Override
    public void run() {
        System.out.println("Hello from Anonymous Class!");
    }
};
r.run();

输出:

Hello from Anonymous Class!

{} 表示我们即时定义了一个实现 Runnable 接口的类,并且立刻创建了该类的对象。


posted @ 2025-08-31 11:32  AlphaGeek  阅读(10)  评论(0)    收藏  举报