web-dev-qa-db-ja.com

Java 8 CompletableFuture例外的にメソッドの驚くべき動作

Java 8 CompletableFuture.exceptionallyメソッドの奇妙な動作に遭遇しました。このコードを実行すると、正常に動作し、Java.lang.RuntimeExceptionを出力します。

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

future.completeExceptionally(new RuntimeException());

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

しかし、将来の処理にthenApplyなどの別のステップを追加すると、例外タイプはJava.util.concurrent.CompletionExceptionに変更され、元の例外が内部にラップされます。

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

future.completeExceptionally(new RuntimeException());

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

これが起こるべき理由はありますか?私の意見では、それは非常に驚くべきことです。

31
Lukas

この動作 CompletionStage(4番目の箇条書き)のクラスドキュメントで指定されています

メソッド handle は、さらに、ステージが置換結果を計算できるようにします。これにより、他の依存ステージによるさらなる処理が可能になります。他のすべての場合、ステージの計算が(チェックされていない)例外またはエラーで突然終了した場合、その完了を必要とするすべての依存ステージも例外を完了し、例外を保持します CompletionException その原因として。

exceptionallyを呼び出したステージが失敗したか、そのいずれかがwantであるかどうかを知りたいと考えても驚くにはあたらない直接または間接の前提条件。

30
Holger

はい、動作は予期されていますが、前のステージのいずれかからスローされた元の例外が必要な場合は、単にこれを使用できます

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