CompletableFuture<T> 类:join() 与 get()

问题描述 投票:0回答:3

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());
}

我已经尝试过这两种方法,但我发现结果没有差异。

java java-8 completable-future
3个回答
190
投票

唯一的区别是方法如何抛出异常。

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()实现。


16
投票

除了 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();
}

您可以参考此文档以获取更多信息。

  1. join() 在 CompletableFuture 中定义,而 get() 来自接口 Future
  2. join() 抛出未检查的异常,而 get() 抛出检查的异常
  3. 您可以中断 get(),然后抛出 InterruptedException
  4. get()方法允许指定最大等待时间

0
投票

其他异常谈论“其中一个方法使用受检查的异常;另一个没有”,这是事实,但忽略了一些微妙之处。

根据阅读文档,让我尝试简洁地分解它:

  • 如果生成该值的底层任务抛出异常,则
    get()
    join()
    都会抛出包含所抛出异常的“包装异常”。在
    get()
    的情况下,包装异常将是
    ExecutionException
    ,这是一个受检查的异常;对于
    join()
    ,它将是
    CompletionException
    ,这是一个未经检查的异常。无论哪种情况,包装的异常(源自底层任务)都是相同的。
  • 看来
    join()
    不能抛出
    InterruptedException
    ;请参阅 CompletableFuture join 与 get Differences 获取示例代码。
  • 任何一种方法都会抛出
    CancellationException

总而言之,

join()
get()
的“简化”形式,它不会抛出
InterruptedException
,并以未经检查的
CompletionException
返回其值。如果您使用
get()
,您不仅会被迫捕获
ExecutionException
(它将包含与
CompletionException
相同的包装异常),而且还会捕获
InterruptedException

© www.soinside.com 2019 - 2024. All rights reserved.