使用join()然后get()的CompletableFuture异常行为

时间:2017-10-30 12:46:37

标签: java exception-handling java-8 completable-future

我的直觉是以下代码是错误的。我相信因为正在使用join(),所以在完成期货时抛出的任何异常都将被取消选中。然后,当调用get()时,将不会有已检查的异常,也不会记录任何错误,并且在故障期间难以诊断错误。

    List<CompletableFuture> list = ImmutableList.of(future1, future2);
    CompletableFuture.allOf(list.toArray(new CompletableFuture[list.size()])).join();

    try {
        result1 = future1.get();
        result2 = future2.get();

    } catch (InterruptedException | ExecutionException e) {
        // will this ever run if join() is already called?
    }

我查看了CompletableFuture的文档但未找到我问题的确切答案。我在这里问,然后将阅读源代码。

我能看到catch块代码运行的唯一原因是,如果以某种方式检查异常可以保存在某些执行上下文中而不是在join()中抛出(或者由未经检查的异常抛出),然后再次抛出get()之后的某些形式。这对我来说似乎不太可能。

所以我的最终问题是,catch块代码是否会运行?

2 个答案:

答案 0 :(得分:3)

joinget方法都是阻塞方法,它依赖于完成信号并返回结果T。处理这段代码: -

一方面,当线程在等待过程中被中断时,InterruptedException可能被抛出get,这里的等待已经由join方法完成。

另外,如join方法文档

中所述
/**
 * ... if a
 * computation involved in the completion of this
 * CompletableFuture threw an exception, this method throws an
 * (unchecked) {@link CompletionException} with the underlying
 * exception as its cause.
 */

因此,另一方面,只有当未来异常完成时,您的ExecutionException futureN.get()才会被抛出。由于未来如果执行异常将最终为CompletionException调用join投掷,它将无法到达catch块或为此try阻止。

答案 1 :(得分:0)

是的,代码永远不会到达,但这并不会使代码错误&#34;。

首先,让我们试一试......

    CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
        throw new IllegalArgumentException();
    });
    try
    {
        CompletableFuture.allOf(future1).join();
    }
    catch (Exception e1)
    {
        System.out.println("I'd exit here."); // *1
    }

    try
    {
        future1.get();
    }
    catch (InterruptedException | ExecutionException e)
    {
        System.out.println("Entered!");
    }

由于您没有执行try/catch&#34; * 1&#34;,因此异常会导致该方法退出,永远不会达到get();所以永远不会执行第二个catch子句。

然而,catch仍然是必要的,因为编译器无法知道以前的调用序列。

这样做的更简单的方法就是这样:

    CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
        throw new IllegalArgumentException();
    });
    try
    {
        CompletableFuture.allOf(future1).join();
        future1.get();
    }
    catch (CompletionException e1) // this is unchecked, of course
    {
        System.out.println("Exception when joining");
    }
    catch (InterruptedException | ExecutionException e)
    {
        System.out.println("Exception when getting");
    }