Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8211010

Add exception handling methods to CompletionStage and CompletableFuture

XMLWordPrintable

    • Icon: CSR CSR
    • Resolution: Approved
    • Icon: P4 P4
    • 12
    • core-libs
    • None
    • source, behavioral
    • minimal
    • Hide
      It is conceivable but very unlikely that the new methods overlap existing methods defined in other CompletionStage implementations in ways that would lead to overload ambiguities. Also, the new methods have default implementations in CompletionStage in terms of other existing methods (they also have more efficient implementations in CompletableFuture), in ways that might uncover existing errors.
      Show
      It is conceivable but very unlikely that the new methods overlap existing methods defined in other CompletionStage implementations in ways that would lead to overload ambiguities. Also, the new methods have default implementations in CompletionStage in terms of other existing methods (they also have more efficient implementations in CompletableFuture), in ways that might uncover existing errors.
    • Java API

      Summary

      People have complained about lack of some exception-handling methods. This CR adds them.

      Problem

      The CompletionStage interface and CompletableFuture implementation lack some methods for dealing with exceptional outcomes that users need and expect based on presence of related non-exception-handling methods.

      Solution

      Add methods to cover all variants of exceptionally{Compose}{Async}:

      exceptionally(Function<Throwable, ? extends T> f) // already exists
      exceptionallyAsync(Function<Throwable, ? extends T> f);
      exceptionallyAsync(Function<Throwable, ? extends T> f, Executor e);
      exceptionallyCompose(Function<Throwable, ? extends CompletionStage<T>> f);
      exceptionallyComposeAsync(Function<Throwable, ? extends CompletionStage<T>> f);
      exceptionallyComposeAsync(Function<Throwable, ? extends CompletionStage<T>> f, Executor e);

      Specification

      /**
       * Returns a new CompletionStage that, when this stage completes
       * exceptionally, is executed with this stage's exception as the
       * argument to the supplied function, using this stage's default
       * asynchronous execution facility.  Otherwise, if this stage
       * completes normally, then the returned stage also completes
       * normally with the same value.
       *
       * @implSpec The default implementation invokes {@link #handle},
       * relaying to {@link #handleAsync} on exception, then {@link
       * #thenCompose} for result.
       *
       * @param fn the function to use to compute the value of the
       * returned CompletionStage if this CompletionStage completed
       * exceptionally
       * @return the new CompletionStage
       * @since 12
       */
      public default CompletionStage<T> exceptionallyAsync
          (Function<Throwable, ? extends T> fn) {
          return handle((r, ex) -> (ex == null)
                        ? this
                        : this.<T>handleAsync((r1, ex1) -> fn.apply(ex1)))
              .thenCompose(Function.identity());
      }
      
      /**
       * Returns a new CompletionStage that, when this stage completes
       * exceptionally, is executed with this stage's exception as the
       * argument to the supplied function, using the supplied Executor.
       * Otherwise, if this stage completes normally, then the returned
       * stage also completes normally with the same value.
       *
       * @implSpec The default implementation invokes {@link #handle},
       * relaying to {@link #handleAsync} on exception, then {@link
       * #thenCompose} for result.
       *
       * @param fn the function to use to compute the value of the
       * returned CompletionStage if this CompletionStage completed
       * exceptionally
       * @param executor the executor to use for asynchronous execution
       * @return the new CompletionStage
       * @since 12
       */
      public default CompletionStage<T> exceptionallyAsync
          (Function<Throwable, ? extends T> fn, Executor executor) {
          return handle((r, ex) -> (ex == null)
                        ? this
                        : this.<T>handleAsync((r1, ex1) -> fn.apply(ex1), executor))
              .thenCompose(Function.identity());
      }
      
      /**
       * Returns a new CompletionStage that, when this stage completes
       * exceptionally, is composed using the results of the supplied
       * function applied to this stage's exception.
       *
       * @implSpec The default implementation invokes {@link #handle},
       * invoking the given function on exception, then {@link
       * #thenCompose} for result.
       *
       * @param fn the function to use to compute the returned
       * CompletionStage if this CompletionStage completed exceptionally
       * @return the new CompletionStage
       * @since 12
       */
      public default CompletionStage<T> exceptionallyCompose
          (Function<Throwable, ? extends CompletionStage<T>> fn) {
          return handle((r, ex) -> (ex == null)
                        ? this
                        : fn.apply(ex))
              .thenCompose(Function.identity());
      }
      
      /**
       * Returns a new CompletionStage that, when this stage completes
       * exceptionally, is composed using the results of the supplied
       * function applied to this stage's exception, using this stage's
       * default asynchronous execution facility.
       *
       * @implSpec The default implementation invokes {@link #handle},
       * relaying to {@link #handleAsync} on exception, then {@link
       * #thenCompose} for result.
       *
       * @param fn the function to use to compute the returned
       * CompletionStage if this CompletionStage completed exceptionally
       * @return the new CompletionStage
       * @since 12
       */
      public default CompletionStage<T> exceptionallyComposeAsync
          (Function<Throwable, ? extends CompletionStage<T>> fn) {
          return handle((r, ex) -> (ex == null)
                        ? this
                        : this.handleAsync((r1, ex1) -> fn.apply(ex1))
                          .thenCompose(Function.identity())
          ).thenCompose(Function.identity());
      }
      
      /**
       * Returns a new CompletionStage that, when this stage completes
       * exceptionally, is composed using the results of the supplied
       * function applied to this stage's exception, using the
       * supplied Executor.
       *
       * @implSpec The default implementation invokes {@link #handle},
       * relaying to {@link #handleAsync} on exception, then {@link
       * #thenCompose} for result.
       *
       * @param fn the function to use to compute the returned
       * CompletionStage if this CompletionStage completed exceptionally
       * @param executor the executor to use for asynchronous execution
       * @return the new CompletionStage
       * @since 12
       */
      public default CompletionStage<T> exceptionallyComposeAsync
          (Function<Throwable, ? extends CompletionStage<T>> fn,
           Executor executor) {
          return handle((r, ex) -> (ex == null)
                        ? this
                        : this.handleAsync((r1, ex1) -> fn.apply(ex1), executor)
                          .thenCompose(Function.identity())
          ).thenCompose(Function.identity());
      }

            martin Martin Buchholz
            dl Doug Lea
            Chris Hegarty, Martin Buchholz
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Created:
              Updated:
              Resolved: