completablefuture unirse vs obtener

91

¿Cuál es la diferencia entre CompletableFuture.get()y CompletableFuture.join()?

A continuación se muestra mi 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());
}

He intentado con ambos métodos pero no veo diferencia en el resultado.

Nomeswaran
fuente
9
get()requiere que detecte las excepciones marcadas. Debería notar la diferencia cuando cambie de get()a join(), ya que inmediatamente obtendrá un error del compilador que indica que ni InterruptedExceptionni se ExecutionExceptionincluyen en el trybloque.
Holger
5
@ holi-java: join()no se puede interrumpir.
Holger
@Holger sí, señor. Descubrí que no puedo interrumpir la tarea.
holi-java
8
Bien getexiste, porque CompletableFutureimplementa la Futureinterfaz que lo exige. join()lo más probable es que se haya introducido, para evitar la necesidad de detectar excepciones marcadas en expresiones lambda al combinar futuros. En todos los demás casos de uso, siéntase libre de usar lo que prefiera.
Holger
1
¿Realmente tiene sentido usar join o get como bloque de ambos en el hilo? ¿No podemos, en cambio, hacer esto asincrónico utilizando otros métodos de composición para crear una cadena de funciones asincrónicas? Por supuesto, depende de la funcionalidad. Pero en el caso de, por ejemplo, un método de servicio en spring llamado por un método de controlador que devuelve un futuro completable, tiene más sentido no llamar a get o unirse al método de servicio.
Shailesh Vaishampayan

Respuestas:

105

la única diferencia es cómo los métodos arrojan excepciones. get()se declara en la Futureinterfaz como

V get() throws InterruptedException, ExecutionException;

Las excepciones son excepciones marcadas, lo que significa que deben manejarse en su código. Como puede ver en su código, un generador de código automático en su IDE le preguntó si debía crear un bloque try-catch en su nombre.

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

El join()método no arroja excepciones marcadas .

public T join()

En su lugar, arroja CompletionException sin marcar. Por lo tanto, no necesita un bloque de prueba y captura y, en su lugar, puede aprovechar completamente el exceptionally()método cuando usa la List<String> processfunción discutida

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

Puede encontrar ambos get()y la join()implementación aquí

Dawid Wróblewski
fuente