我的直觉是以下代码是错误的。我相信因为正在使用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块代码是否会运行?
答案 0 :(得分:3)
join
和get
方法都是阻塞方法,它依赖于完成信号并返回结果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");
}