completablefuture rejoindre vs obtenir

92

Quelle est la différence entre CompletableFuture.get()et CompletableFuture.join()?

Voici mon code:

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

J'ai essayé les deux méthodes mais je ne vois aucune différence de résultat.

Nomeswaran
la source
9
get()vous oblige à intercepter les exceptions vérifiées. Vous devriez remarquer la différence lorsque vous passez de get()à join(), car vous obtiendrez immédiatement une erreur de compilation indiquant que ni InterruptedExceptionni ne ExecutionExceptionsont jetés dans le trybloc.
Holger
5
@ holi-java: join()ne peut pas être interrompu.
Holger
@Holger oui, monsieur. J'ai trouvé que je ne pouvais pas interrompre la tâche.
holi-java
8
Eh bien getexiste, car CompletableFutureimplémente l' Futureinterface qui le commande. join()le plus probable a été introduit, pour éviter d'avoir à intercepter les exceptions vérifiées dans les expressions lambda lors de la combinaison de futures. Dans tous les autres cas d'utilisation, n'hésitez pas à utiliser ce que vous préférez.
Holger
1
Est-il vraiment judicieux d'utiliser join ou get en tant que bloc sur le thread. Ne pouvons-nous pas à la place rendre cela asynchrone en utilisant d'autres méthodes de composition pour créer une chaîne de fonctions asynchrones. Bien sûr, cela dépend de la fonctionnalité. Mais dans le cas, par exemple, d'une méthode de service au printemps appelée par une méthode de contrôleur retournant un futur complet, il est plus logique de ne pas appeler la méthode get ou join in service du tout.
Shailesh Vaishampayan

Réponses:

105

la seule différence est la façon dont les méthodes lancent des exceptions. get()est déclaré dans l' Futureinterface comme

V get() throws InterruptedException, ExecutionException;

Les exceptions sont toutes deux vérifiées, ce qui signifie qu'elles doivent être gérées dans votre code. Comme vous pouvez le voir dans votre code, un générateur de code automatique dans votre IDE vous a demandé s'il fallait créer un bloc try-catch en votre nom.

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

La join()méthode ne lève pas d' exceptions vérifiées .

public T join()

Au lieu de cela, il lance une exception CompletionException non vérifiée. Vous n'avez donc pas besoin d'un bloc try-catch et à la place, vous pouvez pleinement exploiter la exceptionally()méthode lors de l'utilisation de la List<String> processfonction dissociée

CompletableFuture<List<String>> cf = CompletableFuture
    .supplyAsync(this::process)
    .exceptionally(this::getFallbackListOfStrings) // Here you can catch e.g. {@code join}'s CompletionException
    .thenAccept(this::processFurther);

Vous pouvez trouver les deux get()et la join()mise en œuvre ici

Dawid Wróblewski
la source