【问题标题】:Throw Exception in Function apply for CompletableFutures函数中抛出异常适用于 CompletableFutures
【发布时间】:2018-11-14 19:14:34
【问题描述】:

我正在创建一些任务,如下所示(这仅用于演示通常的网络调用):

public class RandomTask implements Function<String, String> {
    private int number;
    private int waitTime;
    private boolean throwError;

    public RandomTask(int number, int waitTime, boolean throwError) {
        this.number = number;
        this.waitTime = waitTime;
        this.throwError = throwError;
    }

    @Override
    public String apply(String s) {
        System.out.println("Job " + number + " started");
        try {
            Thread.sleep(waitTime);

            if (throwError) {
                throw new InterruptedException("Something happened");
            }

        } catch (InterruptedException e) {
            System.out.println("Error " + e.getLocalizedMessage());
        }

        return "RandomTask " + number + " finished";
    }
}

然后我有一个 Chain 类,我在其中将每个作业的一些任务链接在一起。

static CompletableFuture<String> start(ExecutorService executorService) {
    CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "Foo", executorService)
            .thenApplyAsync(new RandomTask(3, 100, false), executorService)
            .thenApplyAsync(new RandomTask(4, 100, false), executorService);

    return future2;
}

然后我按如下方式启动 2 个链:

  CompletableFuture<Void> combinedFuture = CompletableFuture.allOf(Chain1.start(fixedThreadPool), Chain2.start(fixedThreadPool));
    try {
        combinedFuture.get();
    } catch (InterruptedException | ExecutionException e) {
        e.printStackTrace();
    }

这样两条链同时开始。

现在我想在一个任务中抛出一个异常,并在我调用 combineFuture.get() 的地方捕获它,以便我知道哪个任务在我的链中失败了。

问题是我无法调整函数,因为 CompletableFutures 抱怨这一点。我试过了:

@FunctionalInterface
public interface CheckedFunction<T, R> {
    R apply(T t) throws InterruptedException;
}

但这不起作用。这是不可能的吗?或者我怎样才能实现我的目标?

【问题讨论】:

    标签: java completable-future


    【解决方案1】:

    “这样两条链同时开始。”表示您对CompletableFuture 的工作原理有根本错误的理解。

    异步操作在您创建它们时或在它们的先决条件可用时立即提交给执行器服务。因此,对于没有依赖关系的 supplyAsync,异步操作会直接在 supplyAsync 调用中开始。

    所有,像CompletableFuture.allOf(job1, job2).get() 这样的构造,是根据两个作业创建一个新阶段并等待其完成,因此最终结果只是等待两个作业完成。它确实启动作业。他们已经在运行。等待完成对完成的过程没有影响。

    可以将CompletableFuture 与允许检查异常的自定义函数类型链接起来

    public static <T,R> CompletableFuture<R> thenApplyAsync(
        CompletableFuture<T> f, CheckedFunction<? super T, ? extends R> cf,
        Executor e) {
    
        CompletableFuture<R> r = new CompletableFuture<>();
        f.whenCompleteAsync((v,t) -> {
            try {
                if(t != null) r.completeExceptionally(t);
                else r.complete(cf.apply(v));
            } catch(Throwable t2) {
                r.completeExceptionally(t2);
            }
        }, e);
        return r;
    }
    

    要使用此方法,您必须嵌套它们,而不是链接CompletableFuture 上的调用。例如

    static CompletableFuture<String> start(ExecutorService executorService) {
        CompletableFuture<String> future2 = 
            thenApplyAsync(thenApplyAsync(
                CompletableFuture.supplyAsync(() -> "Foo", executorService),
                new RandomTask(3, 100, false), executorService),
                new RandomTask(4, 100, false), executorService);
    
        return future2;
    }
    

    给定

    public class RandomTask implements CheckedFunction<String, String> {
        private int number, waitTime;
        private boolean throwError;
    
        public RandomTask(int number, int waitTime, boolean throwError) {
            this.number = number;
            this.waitTime = waitTime;
            this.throwError = throwError;
        }
    
        @Override
        public String apply(String s) throws InterruptedException {
            System.out.println("Job " + number + " started");
            Thread.sleep(waitTime);
            if (throwError) {
                throw new InterruptedException("Something happened in "+number);
            }
            return "RandomTask " + number + " finished";
        }
    }
    

    你仍然可以创建两个任务并等待两者都喜欢

    CompletableFuture.allOf(Chain1.start(fixedThreadPool), Chain2.start(fixedThreadPool))
        .join();
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-07-27
      • 1970-01-01
      • 2015-08-26
      • 1970-01-01
      • 1970-01-01
      • 2010-09-09
      相关资源
      最近更新 更多