Functional Java - Interaction between whenComplete and exceptionally

后端 未结 3 755
悲&欢浪女
悲&欢浪女 2021-02-01 19:33

In this code:

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


        
3条回答
  •  日久生厌
    2021-02-01 19:54

    The documentation of whenComplete says:

    Returns a new CompletionStage with the same result or exception as this stage, that executes the given action when this stage completes.

    (emphasis mine)

    This implies that an exception is not swallowed by this stage as it is supposed to have the same result or exception. However, you might be surprised by the fact that subsequent stages will receive the exception of a previous stage wrapped within a CompletionException, as discussed here, so it’s not exactly the same exception:

    CompletableFuture 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());
    

    will print:

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

    Note that you can always append multiple actions on one stage instead of chaining then:

    CompletableFuture 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
    

    Of course, since now there is no dependency between the stage 2a and 2b, there is no ordering between them and in the case of async action, they may run concurrently.

提交回复
热议问题