Does CompletionStage always wrap exceptions in CompletionException?

前端 未结 1 1891
死守一世寂寞
死守一世寂寞 2020-12-06 00:35

The CompletionStage Javadoc states:

[...] if a stage\'s computation terminates abruptly with an (unchecked) exception or error, then all dependent sta

相关标签:
1条回答
  • 2020-12-06 01:02

    Is it possible for these methods to receive an exception other than CompletionException?

    Yes, it is possible and you shouldn't cast to CompletionException without an instanceof check (or a review of your usage).

    Take this example

    CompletableFuture<Void> root = new CompletableFuture<>();
    root.whenComplete((v, t) -> {
        System.out.println(t.getClass()); // class java.io.IOException
    });
    root.completeExceptionally(new IOException("blow it up"));
    

    whenComplete will receive the IOException rather than a CompletionException wrapping it. The same behavior applies to exceptionally and handle.


    A stage's computation is defined in the Javadoc:

    The computation performed by a stage may be expressed as a Function, Consumer, or Runnable (using methods with names including apply, accept, or run, respectively) depending on whether it requires arguments and/or produces results.

    I believe this quote

    if a stage's computation terminates abruptly with an (unchecked) exception or error

    is referring to one of those Function#apply, Consumer#accept, or Runnable#run methods terminating abruptly because of a thrown exception, not because a stage completed exceptionally through some other mechanism.

    Note also that the Javadoc says

    This interface does not define methods for initially creating, forcibly completing normally or exceptionally, probing completion status or results, or awaiting completion of a stage. Implementations of CompletionStage may provide means of achieving such effects, as appropriate

    In other words, the interface allows implementations to complete stages exceptionally without abruptly terminating any computation. I think this allows for new behavior.


    If we extend my example from before

    CompletableFuture<Void> root = new CompletableFuture<>();
    CompletableFuture<Void> child = root.whenComplete((v, t) -> {
        System.out.println(t.getClass()); // class java.io.Exception
    });
    child.whenComplete((v, t) -> {
        System.out.println(t.getClass()); // class java.util.concurrent.CompletionException
    });
    root.completeExceptionally(new IOException("blow it up"));
    

    You'll notice the completion attached to the child receives a CompletionException wrapping the original IOException. This isn't obvious to me from the Javadoc, which states

    Returns a new CompletionStage with the same result or exception as this stage

    All in all, it seems like the raw exception from a completeExceptionally is passed down to direct dependents, while dependents of dependents receive an enclosing CompletionException.

    0 讨论(0)
提交回复
热议问题