get()
类的join()
和CompletableFuture<T>
方法有什么区别?
下面是我的代码:
List<String> process() {
List<String> messages = Arrays.asList("Msg1", "Msg2", "Msg3", "Msg4", "Msg5", "Msg6", "Msg7", "Msg8", "Msg9",
"Msg10", "Msg11", "Msg12");
MessageService messageService = new MessageService();
ExecutorService executor = Executors.newFixedThreadPool(4);
List<String> mapResult = new ArrayList<>();
CompletableFuture<?>[] fanoutRequestList = new CompletableFuture[messages.size()];
int count = 0;
for (String msg : messages) {
CompletableFuture<?> future = CompletableFuture
.supplyAsync(() -> messageService.sendNotification(msg), executor).exceptionally(ex -> "Error")
.thenAccept(mapResult::add);
fanoutRequestList[count++] = future;
}
try {
CompletableFuture.allOf(fanoutRequestList).get();
//CompletableFuture.allOf(fanoutRequestList).join();
} catch (InterruptedException | ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return mapResult.stream().filter(s -> !s.equalsIgnoreCase("Error")).collect(Collectors.toList());
}
我已经尝试过这两种方法,但我发现结果没有差异。
唯一的区别是方法如何抛出异常。
get()
在 Future
接口中声明为:
V get() throws InterruptedException, ExecutionException;
这些异常都是 checked 异常,这意味着它们需要在代码中处理。正如您在代码中看到的,IDE 中的自动代码生成器要求代表您创建 try-catch 块。
try {
CompletableFuture.allOf(fanoutRequestList).get()
} catch (InterruptedException | ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
join()
方法不会抛出checked异常。
public T join()
它会抛出 unchecked
CompletionException
。因此,您不需要 try-catch 块,而是在使用所讨论的 exceptionally()
函数时完全利用 List<String> process
方法
CompletableFuture<List<String>> cf = CompletableFuture
.supplyAsync(this::process)
.exceptionally(this::getFallbackListOfStrings) // Here you can catch e.g. {@code join}'s CompletionException
.thenAccept(this::processFurther);
您可以在
这里找到
get()
和join()
实现。
除了 Dawid 提供的答案之外,get 方法还有两种形式:
get()
get(Long timeout, TimeUnit timeUnit)
第二个 get 将等待时间作为参数,并最多等待提供的等待时间。
try {
System.out.println(cf.get(1000, TimeUnit.MILLISECONDS));
} catch (InterruptedException | ExecutionException | TimeoutException ex) {
ex.printStackTrace();
}
您可以参考此文档以获取更多信息。
其他异常谈论“其中一个方法使用受检查的异常;另一个没有”,这是事实,但忽略了一些微妙之处。
根据阅读文档,让我尝试简洁地分解它:
get()
和 join()
都会抛出包含所抛出异常的“包装异常”。在 get()
的情况下,包装异常将是 ExecutionException
,这是一个受检查的异常;对于 join()
,它将是 CompletionException
,这是一个未经检查的异常。无论哪种情况,包装的异常(源自底层任务)都是相同的。join()
不能抛出InterruptedException
;请参阅 CompletableFuture join 与 get Differences 获取示例代码。CancellationException
。总而言之,
join()
是get()
的“简化”形式,它不会抛出InterruptedException
,并以未经检查的CompletionException
返回其值。如果您使用 get()
,您不仅会被迫捕获 ExecutionException
(它将包含与 CompletionException
相同的包装异常),而且还会捕获 InterruptedException
。