简单介绍一下CompletableFuture,从最简单的用法介绍,

文章目录

      • [1. 最简单的创建方式:提交一个异步任务](#1. 最简单的创建方式:提交一个异步任务)
      • [2. 升级玩法:做完一件事,自动做下一件事(链式调用)](#2. 升级玩法:做完一件事,自动做下一件事(链式调用))
        • [`thenApply` ------ 转换结果](#thenApply —— 转换结果)
        • [`thenAccept` ------ 消费结果](#thenAccept —— 消费结果)
      • [3. 应对意外:异常处理](#3. 应对意外:异常处理)
      • 核心总结

在 Java 的并发编程中,CompletableFuture 就像是一个承诺(Promise)。它代表了一个异步计算的结果:这个结果现在可能还没好,但等会儿好了,它会自动通知你,或者直接帮你执行下一步。

在它出现之前(Java 8 之前),我们用 Future,但它有个致命的大坑------你必须死等它结束(调用 .get() 会阻塞线程),或者不停地去轮询。而 CompletableFuture 彻底解放了我们,让我们可以用链式调用写出优雅的异步代码。


1. 最简单的创建方式:提交一个异步任务

如果你只是想把一个耗时的任务扔到后台去执行,不想卡住主线程,最常用的是 runAsync(无返回值)和 supplyAsync(有返回值)。

java 复制代码
import java.util.concurrent.CompletableFuture;

public class SimpleDemo {
    public static void main(String[] args) throws Exception {
        // 1. 扔一个有返回值的异步任务给后台(默认在 ForkJoinPool 线程池执行)
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            try { Thread.sleep(2000); } catch (InterruptedException e) {} // 模拟耗时 2 秒
            return "做好了!";
        });

        System.out.println("主线程继续做别的事...");

        // 2. 强行获取结果(这步会阻塞,直到后台做完)
        String result = future.get(); 
        System.out.println("拿到结果: " + result);
    }
}

2. 升级玩法:做完一件事,自动做下一件事(链式调用)

CompletableFuture 最厉害的地方在于,你可以像接水管一样,把好几个步骤串联起来。前一步的结果会自动传给下一步。

thenApply ------ 转换结果

收到上一步的结果,处理一下,再返回一个新结果。

java 复制代码
CompletableFuture.supplyAsync(() -> "hello")
    .thenApply(result -> result + " world")   // 收到 "hello",加工成 "hello world"
    .thenApply(String::toUpperCase)          // 收到 "hello world",变成大写
    .thenAccept(System.out::println);        // 最终打印: HELLO WORLD
thenAccept ------ 消费结果

收到上一步的结果,把它用掉,没有返回值(通常作为链路的终点)。

java 复制代码
CompletableFuture.supplyAsync(() -> "外卖到了")
    .thenAccept(food -> System.out.println("开吃: " + food));

3. 应对意外:异常处理

异步代码最怕执行到一半悄悄报错,你还不知道。CompletableFuture 提供了很温柔的异常捕获机制:exceptionally。它就像 try-catch,如果前面任何一步崩了,都会掉进这里,并且可以给一个兜底的默认值。

java 复制代码
CompletableFuture.supplyAsync(() -> {
        if (true) { throw new RuntimeException("厨房着火了!"); }
        return "做好的菜";
    })
    .exceptionally(ex -> {
        System.out.println("发生异常: " + ex.getMessage());
        return "方便面(兜底方案)"; // 报错了就吃方便面
    })
    .thenAccept(food -> System.out.println("最终食物: " + food));

核心总结

你可以把它的常用 API 分成三类来记:

动作类型 API 命名规律 特点
开启任务 supplyAsync(...) / runAsync(...) 把任务扔进后台线程池
接续处理 thenApply(...) 拿到上一步的结果,加工并返回新结果
收尾消费 thenAccept(...) 拿到上一步的结果,消费掉,不返回新结果
救场兜底 exceptionally(...) 前面出错时触发,返回一个安全的兜底值
相关推荐
瑞雪兆丰年兮5 分钟前
JavaWeb-day11-SpringBootWeb案例(文件上传)
java·运维·服务器·javaweb·oss
Highcharts.js37 分钟前
Highcharts智能数据分析平台Orbit 多语言配置技术文档
java·前端·javascript·highcharts·orbit·智能数据分析·设置文档
Rain的Java大神之路1 小时前
设计一套生产级 API 接口:从契约、安全、幂等到限流,我踩过的坑都在这了
java·后端·面试
SimonKing1 小时前
零配置也能白嫖前沿大模型!dsh-our-free-model插件真香警告
java·后端·程序员
nice_lcj5201 小时前
【从零理解 Spring AI · 15】让检索更准:先宽召回,再精排序
java·后端·rag·spring ai·ai应用开发·检索优化·重排序
杨凯凡2 小时前
Spring Boot 链路追踪实战:Micrometer、TraceId 与异步线程上下文传播
java·spring boot·后端
计算机毕设定制辅导-无忧学长2 小时前
《基于Spring Boot的迷游哈游戏综合服务平台的开发》
java·vue.js·spring boot·mysql·迷游哈游戏综合服务平台
非优秀程序员11 小时前
第04章 邮箱大战,163 与 QQ 的暗战|《互联网产品恩仇录》
java·vue.js·架构
知已难寻12 小时前
Docker 入门:容器技术与 Docker 基础
java·运维·服务器·docker·云原生·容器
文丑颜不良啊14 小时前
LeetCode2481~2500题目解析
java·leetcode