Besoin de confirmer quelque chose. Le code suivant:
CompletableFuture
.supplyAsync(() -> {return doSomethingAndReturnA();})
.thenApply(a -> convertToB(a));
serait le même que:
CompletableFuture
.supplyAsync(() -> {
A a = doSomethingAndReturnA();
convertToB(a);
});
Droite?
De plus, deux autres questions suivent: "y a-t-il une raison pour laquelle nous utiliserions thenApply
?"
1) avoir un gros code pour la conversion?
o
2) Besoin de réutiliser le bloc lambda dans d'autres endroits?
Ce n'est pas la même chose . Dans le deuxième exemple où thenApply
n'est pas utilisé, il est certain que l'appel à convertToB
est exécuté dans le même thread que la méthode doSomethingAndReturnA
.
Mais, dans le premier exemple, lorsque la méthode thenApply
est utilisée, d'autres choses peuvent se produire.
Tout d'abord, si le CompletableFuture
qui exécute le doSomethingAndReturnA
est terminé, l'invocation du thenApply
aura lieu dans le thread de l'appelant. Si le CompletableFutures
n'est pas terminé, le Function
passé à thenApply
sera invoqué dans le même thread que doSomethingAndReturnA
.
Déroutant? Eh bien cet article pourrait être utile (merci @SotiriosDelimanolis pour le lien).
J'ai fourni un court exemple qui illustre le fonctionnement de thenApply
.
public class CompletableTest {
public static void main(String... args) throws ExecutionException, InterruptedException {
final CompletableFuture<Integer> future = CompletableFuture
.supplyAsync(() -> doSomethingAndReturnA())
.thenApply(a -> convertToB(a));
future.get();
}
private static int convertToB(final String a) {
System.out.println("convertToB: " + Thread.currentThread().getName());
return Integer.parseInt(a);
}
private static String doSomethingAndReturnA() {
System.out.println("doSomethingAndReturnA: " + Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "1";
}
}
Et la sortie est:
doSomethingAndReturnA: ForkJoinPool.commonPool-worker-1
convertToB: ForkJoinPool.commonPool-worker-1
Ainsi, lorsque la première opération est lente (c'est-à-dire que le CompletableFuture
n'est pas encore terminé), les deux appels se produisent dans le même thread. Mais si nous supprimions le Thread.sleep
- appel depuis doSomethingAndReturnA
la sortie (peut) être comme ceci:
doSomethingAndReturnA: ForkJoinPool.commonPool-worker-1
convertToB: main
Notez que l'appel convertToB
est dans le thread main
.
thenApply()
est une fonction de rappel, qui sera exécutée lorsque supplyAsync()
renverra une valeur.
Dans l'extrait de code 2, le thread qui a appelé doSomethingAndReturnA()
attend que la fonction soit exécutée et renvoie les données.
Mais dans certains cas exceptionnels (comme faire un appel Webservice et attendre une réponse), le thread doit attendre long le temps pour obtenir la réponse, ce qui consomme beaucoup de ressources de calcul système (juste attendre la réponse) .
Pour éviter cela, CompletableFuture
est livré avec la fonction callback, où une fois la doSomethingAndReturnA()
invoquée, un thread séparé se chargera d'exécuter doSomethingAndReturnA()
et le thread appelant principal continuera à effectuer d'autres opérations sans attendre le retour de la réponse.
Une fois que la réponse de doSomethingAndReturnA
est disponible, la méthode de rappel sera invoquée (c'est-à-dire thenApply()
)