MST

星途 面试题库

面试题:Java中CompletableFuture thenCombine的高级难度面试题

在一个复杂的业务场景中,有三个异步任务,任务A返回一个用户对象(包含姓名和年龄),任务B返回用户的地址,任务C返回用户的联系方式。要求使用CompletableFuture的thenCombine等方法,将这三个任务的结果合并为一个包含完整用户信息(姓名、年龄、地址、联系方式)的新对象。并且需要处理任务执行过程中可能出现的异常情况,确保即使某个任务失败,整个流程也能有合理的错误处理机制。请编写完整的Java代码实现,并说明在这种场景下使用thenCombine的优势和注意事项。
26.1万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

Java代码实现

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

class User {
    private String name;
    private int age;
    private String address;
    private String contact;

    public User(String name, int age, String address, String contact) {
        this.name = name;
        this.age = age;
        this.address = address;
        this.contact = contact;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", address='" + address + '\'' +
                ", contact='" + contact + '\'' +
                '}';
    }
}

public class CompletableFutureExample {

    public static CompletableFuture<User> getUserInfo() {
        // 模拟异步任务A
        CompletableFuture<User> taskA = CompletableFuture.supplyAsync(() -> {
            // 模拟获取用户对象
            return new User("John", 30, null, null);
        });

        // 模拟异步任务B
        CompletableFuture<String> taskB = CompletableFuture.supplyAsync(() -> {
            // 模拟获取用户地址
            return "123 Main St";
        });

        // 模拟异步任务C
        CompletableFuture<String> taskC = CompletableFuture.supplyAsync(() -> {
            // 模拟获取用户联系方式
            return "123-456-7890";
        });

        return taskA.thenCombine(taskB, (user, address) -> {
            user.address = address;
            return user;
        }).thenCombine(taskC, (user, contact) -> {
            user.contact = contact;
            return user;
        }).exceptionally(ex -> {
            System.out.println("任务执行出现异常: " + ex.getMessage());
            return null;
        });
    }

    public static void main(String[] args) {
        try {
            User user = getUserInfo().get();
            if (user != null) {
                System.out.println(user);
            }
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
    }
}

使用thenCombine的优势

  1. 简洁的异步任务组合thenCombine方法允许我们以一种链式调用的方式,简洁地将多个异步任务的结果进行合并。相比于传统的回调地狱或者手动管理多个线程和锁,这种方式代码结构更加清晰,易于理解和维护。
  2. 异步非阻塞:CompletableFuture本身基于异步和非阻塞的特性,thenCombine也继承了这一优点。它不会阻塞主线程,允许主线程在等待异步任务完成的同时继续执行其他操作,提高了程序的整体性能和响应性。
  3. 异常处理方便:通过exceptionally方法,可以方便地在链式调用中统一处理任务执行过程中可能出现的异常。这种集中式的异常处理机制使得代码更健壮,并且易于排查和定位问题。

注意事项

  1. 任务依赖关系:在使用thenCombine时,需要确保任务之间的依赖关系清晰。如果任务的执行顺序或者结果的合并逻辑出现错误,可能会导致程序逻辑错误。例如,如果任务B依赖于任务A的结果,而代码中没有正确处理这种依赖关系,可能会得到不正确的合并结果。
  2. 异常处理范围:虽然exceptionally方法提供了方便的异常处理机制,但需要注意异常处理的范围。它只会捕获当前CompletableFuture链中抛出的异常,如果异常发生在更外层或者其他独立的异步任务中,可能需要额外的处理机制。
  3. 内存管理:由于CompletableFuture在异步执行过程中可能会创建多个线程和对象,需要注意内存管理。特别是在高并发场景下,如果大量使用CompletableFuture而不及时释放资源,可能会导致内存泄漏和性能问题。
  4. 结果的一致性:在多个异步任务并行执行并合并结果时,要确保结果的一致性。例如,如果任务A和任务B都对同一个共享资源进行修改,需要考虑线程安全问题,以避免数据竞争和不一致的结果。