Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams According to the documentation they're very similar, but completeExceptionally would not cause get to throw an exception if the task had already completed. obtrudeException seems to cause get to throw an exception regardless. matt Sep 4, 2021 at 11:44

The difference is subtle but important. From the official documentation :

  • completeExceptionally​
  • If not already completed , causes invocations of get() and related methods to throw the given exception.

  • obtrudeException
  • Forcibly causes subsequent invocations of method get() and related methods to throw the given exception, whether or not already completed . [...]

    So they differ in their behavior regarding CompletableFuture s that are already completed .

    Basically, a future can either be completed or still pending (not completed). When you call completeExceptionally or obtrudeException , the behavior differs depending on the state of the future at that point in time.

    Already completed future

    Consider this example where the future is already completed at the moment of calling the method:

    CompletableFuture<String> future = CompletableFuture.completedFuture("hello world");
    future.completeExceptionally(new RuntimeException("Oh noes!"));
    System.out.println(future.get()); // Prints "hello world" just fine
    

    versus

    CompletableFuture<String> future = CompletableFuture.completedFuture("hello world");
    future.obtrudeException(new RuntimeException("Oh noes!"));
    System.out.println(future.get()); // Throws the exception
    

    Not completed future

    And in case the future is not completed yet, they will both throw an exception:

    CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> { 
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
        return "hello world";
    future.completeExceptionally(new RuntimeException("Oh noes!"));
    System.out.println(future.get());
    
    CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> { 
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
        return "hello world";
    future.obtrudeException(new RuntimeException("Oh noes!"));
    System.out.println(future.get());
    

    complete and obtrudeValue

    Likewise there are also the methods complete and obtrudeValue which behave in the same way, but instead of throwing an exception, you can supply a value instead.

    So complete basically completes the future with the given value, in case the future is not done yet, otherwise it does not do anything.

    While obtrudeValue will supply the given value regardless, so it resets or cancels whatever the future already computed and replaces it by the given value instead.

    It sounds like I would always need the complete or completeExceptionally behavior. Could you add a case when we would actually want to use obtrudeValue or obtrudeException – RBz Sep 4, 2021 at 12:32 @RBz I have never encountered one myself but the documentation hints at "error recovery". So I could imagine a case where, during your future computation, something goes wrong somewhere else and you want to basically cancel your future computations and replace the result with something entirely different. In that case, obtrudeXXX could be helpful since it is a "regardless of what the future is currently doing, do this instead now" – Zabuzard Sep 4, 2021 at 12:34 Maybe debugging. Consider a scenario where you want to verify your assumption that a future won’t be used after a certain point. Then, you could change it to a specific exception or marker value that would deliberately break any code that tries to use the future. But I also never used the obtrude… methods. – Holger Sep 6, 2021 at 8:20

    completeExceptionally:

    completableFuture.completeExceptionally(
      new RuntimeException("Calculation failed!"));
    completableFuture.get(); //exception will be thrown whether `completableFuture` was not already completed.
    

    obtrudeException:

    completableFuture.obtrudeException(
      new RuntimeException("Calculation failed!"));
    completableFuture.get(); //exception will be thrown **whether or not** `completableFuture` was completed.
            

    Thanks for contributing an answer to Stack Overflow!

    • Please be sure to answer the question. Provide details and share your research!

    But avoid

    • Asking for help, clarification, or responding to other answers.
    • Making statements based on opinion; back them up with references or personal experience.

    To learn more, see our tips on writing great answers.