Completetablefuture join vs get

95

В чем разница между CompletableFuture.get()и CompletableFuture.join()?

Ниже мой код:

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

Я пробовал оба метода, но не вижу разницы в результате.

Номесваран
источник
11
get()требует, чтобы вы перехватили проверенные исключения. Вы должны заметить разницу при переходе с get()на join(), так как вы сразу же получите ошибку компилятора, в которой говорится, что ни один из них InterruptedExceptionне попадает ExecutionExceptionв tryблок.
Holger
5
@ holi-java: join()нельзя прерывать.
Holger
@ Холгер, да, сэр. Я обнаружил, что не могу прервать задание.
holi-java
9
Well getсуществует, потому что CompletableFutureреализует Futureинтерфейс, который его требует. join()скорее всего, был введен, чтобы избежать необходимости перехватывать проверенные исключения в лямбда-выражениях при объединении фьючерсов. Во всех остальных случаях используйте то, что вам больше нравится.
Хольгер
1
Действительно ли имеет смысл использовать объединение или получение в качестве обоих блоков в потоке. Разве вместо этого мы не можем сделать это асинхронным, используя другие методы композиции для создания цепочки асинхронных функций. Конечно, это зависит от функциональности. Но в случае, например, метода службы в Spring, вызываемого методом контроллера, возвращающим завершаемое будущее, имеет смысл вообще не вызывать метод получения или присоединения к методу службы.
Шайлеш Вайшампаян

Ответы:

110

единственная разница в том, как методы генерируют исключения. get()объявлен в Futureинтерфейсе как

V get() throws InterruptedException, ExecutionException;

Оба исключения являются отмеченными исключениями, что означает, что они должны обрабатываться в вашем коде. Как вы можете видеть в своем коде, автоматический генератор кода в вашей среде IDE спрашивает, создавать ли блок try-catch от вашего имени.

try {
  CompletableFuture.allOf(fanoutRequestList).get() 
} catch (InterruptedException | ExecutionException e) {
  // TODO Auto-generated catch block
  e.printStackTrace();
}

join()Метод не выбрасывает отмеченные исключения.

public T join()

Вместо этого он выдает непроверенное исключение CompletionException. Таким образом, вам не нужен блок try-catch, и вместо этого вы можете полностью использовать exceptionally()метод при использовании List<String> processфункции disscused

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()осуществление здесь

Давид Врублевски
источник