completablefuture join vs get


95

Qual'è la differenza tra CompletableFuture.get()e CompletableFuture.join()?

Di seguito il mio codice:

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

Ho provato con entrambi i metodi ma non vedo differenze nel risultato.


11
get()richiede di rilevare le eccezioni selezionate. Dovresti notare la differenza quando cambi da get()a join(), poiché riceverai immediatamente un errore del compilatore che dice che né InterruptedExceptionExecutionExceptionvengono lanciati nel tryblocco.
Holger

5
@ holi-java: join()non può essere interrotto.
Holger

@Holger sì, signore. Ho scoperto di non poter interrompere l'attività.
holi-java

9
Bene getesiste, perché CompletableFutureimplementa l' Futureinterfaccia che lo impone. join()molto probabilmente è stato introdotto, per evitare di dover catturare eccezioni controllate nelle espressioni lambda quando si combinano i futures. In tutti gli altri casi d'uso, sentiti libero di usare quello che preferisci.
Holger

1
Ha davvero senso usare join o get come entrambi i blocchi sul thread. Non possiamo invece renderlo asincrono utilizzando altri metodi di composizione per creare una catena di funzioni asincrone. Ovviamente dipende dalla funzionalità. Ma nel caso, ad esempio, di un metodo di servizio in primavera chiamato dal metodo del controller che restituisce un futuro completo, ha più senso non chiamare affatto il metodo get o join in.
Shailesh Vaishampayan

Risposte:


110

l'unica differenza è il modo in cui i metodi generano le eccezioni. get()è dichiarato Futurenell'interfaccia come

V get() throws InterruptedException, ExecutionException;

Le eccezioni sono entrambe eccezioni controllate, il che significa che devono essere gestite nel codice. Come puoi vedere nel tuo codice, un generatore di codice automatico nel tuo IDE ha chiesto se creare un blocco try-catch per tuo conto.

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

Il join()metodo non genera eccezioni controllate .

public T join()

Invece, genera CompletionException non controllata . Quindi non hai bisogno di un blocco try-catch e invece puoi sfruttare completamente il exceptionally()metodo quando usi la List<String> processfunzione 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);

Puoi trovare entrambi get()e l' join()implementazione qui

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.