web-dev-qa-db-fra.com

Java fonctionnel - Interaction entre whenComplete et exceptionnellement

Dans ce code:

doSomethingThatMightThrowAnException()
  .whenComplete((result, ex) -> doSomethingElse()})
  .exceptionally(ex -> handleException(ex));

Quand il y a une exception à doSomethingThatMightThrowAnException, doSomethingElse et handleException sont-ils exécutés ou l'exception est-elle consommée par whenComplete ou exceptionally?

MODIFIER:

doSomethingThatMightThrowAnException renvoie une CompletableFuture, qui pourrait completeExceptionally. C'est l'exception dont je parle.

14
peco

La documentation de whenComplete dit:

Renvoie un nouveau CompletionStage avec le même résultat ou la même exception que cette étape , qui exécute l'action indiquée à la fin de cette étape.

(c'est moi qui souligne)

Cela implique qu’une exception n’est pas avalée par cette étape car elle est supposée avoir le même résultat ou la même exception. Cependant, vous pourriez être surpris par le fait que les étapes suivantes recevront l’exception d’une étape précédente encapsulée dans une CompletionException, comme discuté ici , ce n’est donc pas exactement la même exception:

CompletableFuture<String> test=new CompletableFuture<>();
test.whenComplete((result, ex) -> System.out.println("stage 2: "+result+"\t"+ex))
    .exceptionally(ex -> { System.out.println("stage 3: "+ex); return ""; });
test.completeExceptionally(new IOException());

imprimera:

stage 2: null   Java.io.IOException
stage 3: Java.util.concurrent.CompletionException: Java.io.IOException

Notez que vous pouvez toujours ajouter plusieurs actions sur une étape au lieu de chaîner ensuite:

CompletableFuture<String> test=new CompletableFuture<>();
test.whenComplete((result, ex) -> System.out.println("stage 2a: "+result+"\t"+ex));
test.exceptionally(ex -> { System.out.println("stage 2b: "+ex); return ""; });
test.completeExceptionally(new IOException());
stage 2b: Java.io.IOException
stage 2a: null  Java.io.IOException

Bien sûr, étant donné qu’il n’ya pas de dépendance entre les étapes 2a et 2b, il n’existe aucun ordre entre elles et, dans le cas d’une action asynchrone, elles peuvent être exécutées simultanément.

18
Holger

La méthode exceptionnellement déclare:

Renvoie une nouvelle CompletableFuture qui est terminée à la fin de cette CompletableFuture, avec le résultat de la fonction donnée de l'exception qui déclenche l'achèvement de cette CompletableFuture lorsqu'elle se termine de manière exceptionnelle. sinon, si cet objet CompletableFuture se termine normalement, l'objet CompletableFuture renvoyé s'achève également normalement avec la même valeur. Remarque: Des versions plus flexibles de cette fonctionnalité sont disponibles à l'aide de méthodes whenComplete et handle.

Ce n'est pas, IMHO écrit dans l'anglais le plus clair, mais je dirais que cela signifie que si une exception est levée, seule l'action exceptionally sera déclenchée. Si aucune exception n'est levée, seule l'action normal sera effectuée.

2
OldCurmudgeon

doSomethingThatMightThrowAnException() est enchaîné avec .whenComplete((result, ex) -> doSomethingElse()}) et .exceptionally(ex -> handleException(ex)); mais s'il lève une exception, il se termine là car aucun objet ne sera transmis dans la chaîne.

N'oubliez pas qu'une exception rejettera l'appelant. Par conséquent, à moins que doSomethingThatMightThrowAnException() ne détecte l'exception en interne, il le rejettera. Si c'est votre classe, vous devriez savoir si elle lance, sinon, vérifiez dans la documentation pour les bibliothèques que vous utilisez.

0
Tuxxy_Thang