Je joue avec les chaînes CompletableFuture et suis tombé sur une situation avec un comportement inattendu (pour moi, au moins): si un CompletableFuture exceptionnel est passé en appel .thenCompose()
, le CompletableFuture résultant sera terminé avec l'exception originale enveloppée au CompletionException
. Il peut être difficile de comprendre sans exemple:Exécution du comportement CompletableFuture souhaité
public static <T> CompletableFuture<T> exceptional(Throwable error) {
CompletableFuture<T> future = new CompletableFuture<>();
future.completeExceptionally(error);
return future;
}
public static void main(String[] args) {
CompletableFuture<Void> exceptional = exceptional(new RuntimeException());
exceptional
.handle((result, throwable) -> {
System.out.println(throwable);
// java.lang.RuntimeException
System.out.println(throwable.getCause());
// null
return null;
});
CompletableFuture
.completedFuture(null)
.thenCompose(v -> exceptional)
.handle((result, throwable) -> {
System.out.println(throwable);
// java.util.concurrent.CompletionException: java.lang.RuntimeException
System.out.println(throwable.getCause());
// java.lang.RuntimeException
return null;
});
}
Bien sûr que je comptais faire face à la même RuntimeException
peu importe combien de transformations étaient avant ou après dans la chaîne. J'ai deux questions:
- Est-ce un comportement attendu?
- Ai-je des options pour conserver l'exception d'origine, sauf pour le déballage manuel?