completablefuture join vs get

95

Qual é a diferença entre CompletableFuture.get()e CompletableFuture.join()?

Abaixo está o meu código:

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

Eu tentei com os dois métodos, mas não vejo diferença no resultado.

Nomeswaran
fonte
11
get()requer que você capture exceções verificadas. Você deve notar a diferença ao mudar de get()para join(), pois imediatamente obterá um erro do compilador dizendo que nem InterruptedExceptione nem ExecutionExceptionsão lançados no trybloco.
Holger
5
@ holi-java: join()não pode ser interrompido.
Holger
@Holger sim, senhor. Descobri que não consigo interromper a tarefa.
holi-java
9
Bem getexiste, porque CompletableFutureimplementa a Futureinterface que o exige. join()provavelmente foi introduzido, para evitar a necessidade de capturar exceções verificadas em expressões lambda ao combinar futuros. Em todos os outros casos de uso, fique à vontade para usar o que preferir.
Holger
1
Realmente faz sentido usar join ou get como os dois blocos no thread. Não podemos, em vez disso, tornar isso assíncrono usando outros métodos de composição para criar uma cadeia de funções assíncronas. Claro que depende da funcionalidade. Mas no caso de, por exemplo, um método de serviço no spring chamado pelo método do controlador retornar um futuro completável, faz mais sentido não chamar get ou join in service.
Shailesh Vaishampayan

Respostas:

110

a única diferença é como os métodos lançam exceções. get()é declarado na Futureinterface como

V get() throws InterruptedException, ExecutionException;

As exceções são exceções verificadas, o que significa que precisam ser tratadas em seu código. Como você pode ver em seu código, um gerador automático de código em seu IDE perguntou se deveria criar o bloco try-catch em seu nome.

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

O join()método não lança exceções verificadas .

public T join()

Em vez disso, ele lança CompletionException desmarcado . Portanto, você não precisa de um bloco try-catch e, em vez disso, pode aproveitar totalmente o exceptionally()método ao usar a List<String> processfunção 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);

Você pode encontrar ambos get()e join()implementação aqui

Dawid Wróblewski
fonte