web-dev-qa-db-fra.com

Comportement surprenant de Java 8 CompletableFuture exceptionnellement méthode

J'ai rencontré un comportement étrange de Java 8 CompletableFuture.exceptionally. Si j'exécute ce code, cela fonctionne très bien et affiche Java.lang.RuntimeException

CompletableFuture<String> future = new CompletableFuture<>();

future.completeExceptionally(new RuntimeException());

future.exceptionally(e -> {
            System.out.println(e.getClass());
            return null;
});

Mais si j'ajoute une autre étape dans le futur traitement comme thenApply, le type d'exception passe à Java.util.concurrent.CompletionException avec l'exception d'origine enveloppée à l'intérieur.

CompletableFuture<String> future = new CompletableFuture<>();

future.completeExceptionally(new RuntimeException());

future.thenApply(v-> v).exceptionally(e -> {
            System.out.println(e);
            return null;
});

Y a-t-il une raison pour que cela se produise? À mon avis, c'est assez surprenant.

31
Lukas

Ce comportement est spécifié dans la documentation de classe de CompletionStage (quatrième puce) :

La méthode handle permet en outre à l'étape de calculer un résultat de remplacement qui peut permettre un traitement ultérieur par d'autres étapes dépendantes. Dans tous les autres cas, si le calcul d'une étape se termine brusquement avec une exception ou une erreur (non vérifiée), toutes les étapes dépendantes nécessitant son achèvement se terminent également exceptionnellement, avec CompletionException contenant l'exception comme sa cause.

Ce n'est pas si surprenant si vous considérez que vous pouvez vouloir savoir si l'étape que vous avez invoquée exceptionally en cas d'échec, ou l'une de ses prérequis directs ou indirects.

30
Holger

oui, le comportement est attendu, mais si vous voulez l'exception d'origine qui a été levée à partir d'une des étapes précédentes, vous pouvez simplement utiliser ceci

CompletableFuture<String> future = new CompletableFuture<>();

future.completeExceptionally(new RuntimeException());

future.thenApply(v-> v).exceptionally(e -> {
        System.out.println(e.getCause()); // returns a throwable back
        return null;
});
7
Gagandeep Kalra