From d4d452264b771969a36c2e1a41fae8c8fab627b3 Mon Sep 17 00:00:00 2001 From: Jerry Lee Date: Sat, 27 Apr 2024 21:05:11 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20reorder=20methods=20=F0=9F=9A=9E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/io/foldright/cffu/Cffu.java | 137 +++-- .../java/io/foldright/cffu/CffuFactory.java | 284 +++++------ .../cffu/CompletableFutureUtils.java | 474 +++++++++--------- .../cffu/CompletableFutureUtilsTest.java | 194 +++---- .../java/io/foldright/cffu/tuple/TupleTest.kt | 24 + .../kotlin/CompletableFutureExtensions.kt | 431 ++++++++-------- .../test/CompletableFutureExtensionsTest.kt | 2 +- 7 files changed, 776 insertions(+), 770 deletions(-) diff --git a/cffu-core/src/main/java/io/foldright/cffu/Cffu.java b/cffu-core/src/main/java/io/foldright/cffu/Cffu.java index 826a1dd2..7893eedc 100644 --- a/cffu-core/src/main/java/io/foldright/cffu/Cffu.java +++ b/cffu-core/src/main/java/io/foldright/cffu/Cffu.java @@ -1288,7 +1288,6 @@ public Cffu exceptionallyAsync(Function fn, Executor */ public Cffu orTimeout(long timeout, TimeUnit unit) { checkMinimalStage(); - CompletableFutureUtils.orTimeout(cf, timeout, unit); return this; } @@ -1304,7 +1303,6 @@ public Cffu orTimeout(long timeout, TimeUnit unit) { */ public Cffu completeOnTimeout(@Nullable T value, long timeout, TimeUnit unit) { checkMinimalStage(); - CompletableFutureUtils.completeOnTimeout(cf, value, timeout, unit); return this; } @@ -1436,6 +1434,64 @@ public Cffu exceptionallyComposeAsync( return reset0(CompletableFutureUtils.exceptionallyComposeAsync(cf, fn, executor)); } + /** + * Returns a new Cffu that, when this cffu completes either normally or exceptionally, + * is executed with this cffu's result and exception as arguments to the supplied function. + *

+ * When this cffu is complete, the given function is invoked with the result (or {@code null} if none) + * and the exception (or {@code null} if none) of this cffu as arguments, + * and the function's result is used to complete the returned cffu. + * + * @param fn the function to use to compute the value of the returned Cffu + * @param the function's return type + * @return the new Cffu + */ + @CheckReturnValue(explanation = "should use the returned Cffu; otherwise, prefer method `whenComplete`") + @Override + public Cffu handle(BiFunction fn) { + return reset0(cf.handle(fn)); + } + + /** + * Returns a new Cffu that, when this cffu completes either normally or exceptionally, + * is executed using {@link #defaultExecutor()}, + * with this cffu's result and exception as arguments to the supplied function. + *

+ * When this Cffu is complete, the given function is invoked with the result (or {@code null} if none) + * and the exception (or {@code null} if none) of this Cffu as arguments, + * and the function's result is used to complete the returned Cffu. + * + * @param fn the function to use to compute the value of the returned Cffu + * @param the function's return type + * @return the new Cffu + */ + @CheckReturnValue(explanation = "should use the returned Cffu; otherwise, prefer method `whenCompleteAsync`") + @Override + public Cffu handleAsync(BiFunction fn) { + return handleAsync(fn, fac.defaultExecutor()); + } + + /** + * Returns a new Cffu that, when this cffu completes either normally or exceptionally, + * is executed using the supplied executor, with this cffu's result and exception + * as arguments to the supplied function. + *

+ * When this cffu is complete, the given function is invoked with the result (or {@code null} if none) + * and the exception (or {@code null} if none) of this cffu as arguments, + * and the function's result is used to complete the returned cffu. + * + * @param fn the function to use to compute the value of the returned cffu + * @param executor the executor to use for asynchronous execution + * @param the function's return type + * @return the new Cffu + */ + @CheckReturnValue(explanation = "should use the returned Cffu; otherwise, prefer method `whenCompleteAsync`") + @Override + public Cffu handleAsync( + BiFunction fn, Executor executor) { + return reset0(cf.handleAsync(fn, executor)); + } + /** * Returns a new Cffu with the same result or exception as this stage, * that executes the given action when this stage completes. @@ -1573,64 +1629,6 @@ public Cffu peekAsync(BiConsumer action, Execut return this; } - /** - * Returns a new Cffu that, when this cffu completes either normally or exceptionally, - * is executed with this cffu's result and exception as arguments to the supplied function. - *

- * When this cffu is complete, the given function is invoked with the result (or {@code null} if none) - * and the exception (or {@code null} if none) of this cffu as arguments, - * and the function's result is used to complete the returned cffu. - * - * @param fn the function to use to compute the value of the returned Cffu - * @param the function's return type - * @return the new Cffu - */ - @CheckReturnValue(explanation = "should use the returned Cffu; otherwise, prefer method `whenComplete`") - @Override - public Cffu handle(BiFunction fn) { - return reset0(cf.handle(fn)); - } - - /** - * Returns a new Cffu that, when this cffu completes either normally or exceptionally, - * is executed using {@link #defaultExecutor()}, - * with this cffu's result and exception as arguments to the supplied function. - *

- * When this Cffu is complete, the given function is invoked with the result (or {@code null} if none) - * and the exception (or {@code null} if none) of this Cffu as arguments, - * and the function's result is used to complete the returned Cffu. - * - * @param fn the function to use to compute the value of the returned Cffu - * @param the function's return type - * @return the new Cffu - */ - @CheckReturnValue(explanation = "should use the returned Cffu; otherwise, prefer method `whenCompleteAsync`") - @Override - public Cffu handleAsync(BiFunction fn) { - return handleAsync(fn, fac.defaultExecutor()); - } - - /** - * Returns a new Cffu that, when this cffu completes either normally or exceptionally, - * is executed using the supplied executor, with this cffu's result and exception - * as arguments to the supplied function. - *

- * When this cffu is complete, the given function is invoked with the result (or {@code null} if none) - * and the exception (or {@code null} if none) of this cffu as arguments, - * and the function's result is used to complete the returned cffu. - * - * @param fn the function to use to compute the value of the returned cffu - * @param executor the executor to use for asynchronous execution - * @param the function's return type - * @return the new Cffu - */ - @CheckReturnValue(explanation = "should use the returned Cffu; otherwise, prefer method `whenCompleteAsync`") - @Override - public Cffu handleAsync( - BiFunction fn, Executor executor) { - return reset0(cf.handleAsync(fn, executor)); - } - //////////////////////////////////////////////////////////////////////////////// //# Read(explicitly) methods of CompletableFuture // @@ -1673,7 +1671,6 @@ public Cffu handleAsync( @Override public T get() throws InterruptedException, ExecutionException { checkMinimalStage(); - return cf.get(); } @@ -1699,7 +1696,6 @@ public T get() throws InterruptedException, ExecutionException { @Override public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { checkMinimalStage(); - return cf.get(timeout, unit); } @@ -1724,7 +1720,6 @@ public T get(long timeout, TimeUnit unit) throws InterruptedException, Execution @Nullable public T join() { checkMinimalStage(); - return cf.join(); } @@ -1767,7 +1762,6 @@ public T join() { @Nullable public T join(long timeout, TimeUnit unit) { checkMinimalStage(); - return CompletableFutureUtils.join(cf, timeout, unit); } @@ -1790,7 +1784,6 @@ public T join(long timeout, TimeUnit unit) { @Nullable public T getNow(T valueIfAbsent) { checkMinimalStage(); - return cf.getNow(valueIfAbsent); } @@ -1814,7 +1807,6 @@ public T getNow(T valueIfAbsent) { @Override public T resultNow() { checkMinimalStage(); - return CompletableFutureUtils.resultNow(cf); } @@ -1832,7 +1824,6 @@ public T resultNow() { @Override public Throwable exceptionNow() { checkMinimalStage(); - return CompletableFutureUtils.exceptionNow(cf); } @@ -1848,7 +1839,6 @@ public Throwable exceptionNow() { @Override public boolean isDone() { checkMinimalStage(); - return cf.isDone(); } @@ -1862,7 +1852,6 @@ public boolean isDone() { @Contract(pure = true) public boolean isCompletedExceptionally() { checkMinimalStage(); - return cf.isCompletedExceptionally(); } @@ -1876,7 +1865,6 @@ public boolean isCompletedExceptionally() { @Override public boolean isCancelled() { checkMinimalStage(); - return cf.isCancelled(); } @@ -1899,7 +1887,6 @@ public boolean isCancelled() { @Override public Future.State state() { checkMinimalStage(); - return cf.state(); } @@ -1916,7 +1903,6 @@ public Future.State state() { @Contract(pure = true) public CffuState cffuState() { checkMinimalStage(); - return CompletableFutureUtils.state(cf); } @@ -1938,7 +1924,6 @@ public CffuState cffuState() { */ public boolean complete(@Nullable T value) { checkMinimalStage(); - return cf.complete(value); } @@ -1963,7 +1948,6 @@ public Cffu completeAsync(Supplier supplier) { */ public Cffu completeAsync(Supplier supplier, Executor executor) { checkMinimalStage(); - CompletableFutureUtils.completeAsync(cf, supplier, executor); return this; } @@ -1976,7 +1960,6 @@ public Cffu completeAsync(Supplier supplier, Executor executor) */ public boolean completeExceptionally(Throwable ex) { checkMinimalStage(); - return cf.completeExceptionally(ex); } @@ -1992,7 +1975,6 @@ public boolean completeExceptionally(Throwable ex) { @Override public boolean cancel(boolean mayInterruptIfRunning) { checkMinimalStage(); - return cf.cancel(mayInterruptIfRunning); } @@ -2188,7 +2170,6 @@ public CompletableFuture cffuUnwrap() { @Contract(pure = true) public int getNumberOfDependents() { checkMinimalStage(); - return cf.getNumberOfDependents(); } @@ -2216,7 +2197,6 @@ public int getNumberOfDependents() { public void obtrudeValue(@Nullable T value) { checkMinimalStage(); checkForbidObtrudeMethods(); - cf.obtrudeValue(value); } @@ -2233,7 +2213,6 @@ public void obtrudeValue(@Nullable T value) { public void obtrudeException(Throwable ex) { checkMinimalStage(); checkForbidObtrudeMethods(); - cf.obtrudeException(ex); } diff --git a/cffu-core/src/main/java/io/foldright/cffu/CffuFactory.java b/cffu-core/src/main/java/io/foldright/cffu/CffuFactory.java index d0c944c1..c5ac38b2 100644 --- a/cffu-core/src/main/java/io/foldright/cffu/CffuFactory.java +++ b/cffu-core/src/main/java/io/foldright/cffu/CffuFactory.java @@ -292,13 +292,10 @@ public final Cffu[] asCffuArray(CompletionStage... stages) { } //////////////////////////////////////////////////////////////////////////////// - //# allOf / anyOf methods - // - allOf*, return Cffu, equivalent to same name methods: - // - CompletableFuture.allOf() - // - CompletableFutureUtils.allOfFastFail() - // - anyOf*, equivalent to same name methods: - // - CompletableFuture.anyOf() - // - CompletableFutureUtils.anyOfSuccess() + //# allOf* methods + // + // - allOf / allOfFastFail + // - allResultsOf / allResultsOfFastFail //////////////////////////////////////////////////////////////////////////////// /** @@ -438,138 +435,6 @@ public Cffu allOfFastFail() { return new0(CompletableFutureUtils.allOfFastFail()); } - /** - * Returns a new Cffu that is completed when any of the given Cffus complete, with the same result.
- * Otherwise, if it completed exceptionally, the returned Cffu also does so, - * with a CompletionException holding this exception as its cause.
- * If no Cffus are provided, returns an incomplete Cffu. - * - * @param cfs the Cffus - * @return a new Cffu that is completed with the result - * or exception from any of the given Cffus when one completes - * @throws NullPointerException if the array or any of its elements are {@code null} - * @see CompletableFuture#anyOf(CompletableFuture[]) - */ - @Contract(pure = true) - @SuppressWarnings("unchecked") - @SafeVarargs - public final Cffu anyOf(Cffu... cfs) { - return anyOf(toCompletableFutureArray((Cffu[]) cfs)); - } - - /** - * This method is the same as {@link #anyOf(Cffu[])} except with overloaded argument type {@link CompletableFuture}. - * - * @param cfs the CompletableFutures - * @return a new Cffu that is completed with the result - * or exception from any of the given CompletableFutures when one completes - * @throws NullPointerException if the array or any of its elements are {@code null} - * @see #anyOf(Cffu[]) - * @see CompletableFuture#anyOf(CompletableFuture[]) - */ - @Contract(pure = true) - @SuppressWarnings("unchecked") - @SafeVarargs - public final Cffu anyOf(CompletableFuture... cfs) { - return (Cffu) new0(CompletableFuture.anyOf(cfs)); - } - - /** - * Provided this overloaded method just for resolving "anyOf is ambiguous" problem - * when call {@code anyOf} with empty arguments: {@code cffuFactory.anyOf()}. - * - * @see #anyOf(Cffu[]) - * @see #anyOf(CompletableFuture[]) - */ - @Contract(pure = true) - public Cffu anyOf() { - return newIncompleteCffu(); - } - - /** - * Returns a new Cffu that is successful when any of the given Cffus success, - * with the same result. Otherwise, all the given Cffus complete exceptionally, - * the returned Cffu also does so, with a CompletionException holding - * an exception from any of the given Cffu as its cause. If no Cffu are provided, - * returns a new Cffu that is already completed exceptionally - * with a CompletionException holding a {@link NoCfsProvidedException} as its cause. - * - * @param cfs the Cffus - * @return a new Cffu - * @throws NullPointerException if the array or any of its elements are {@code null} - */ - @SuppressWarnings({"unchecked", "rawtypes"}) - @SafeVarargs - public final Cffu anyOfSuccess(Cffu... cfs) { - return (Cffu) anyOfSuccess(toCompletableFutureArray((Cffu[]) cfs)); - } - - /** - * Returns a new Cffu that is successful when any of the given CompletableFutures success, - * with the same result. Otherwise, all the given CompletableFutures complete exceptionally, - * the returned Cffu also does so, with a CompletionException holding - * an exception from any of the given CompletableFutures as its cause. If no CompletableFutures are provided, - * returns a new Cffu that is already completed exceptionally - * with a CompletionException holding a {@link NoCfsProvidedException} as its cause. - * - * @param cfs the CompletableFutures - * @return a new Cffu - * @throws NullPointerException if the array or any of its elements are {@code null} - */ - @SafeVarargs - public final Cffu anyOfSuccess(CompletableFuture... cfs) { - return new0(CompletableFutureUtils.anyOfSuccess(cfs)); - } - - /** - * Provided this overloaded method just for resolving "anyOfSuccess is ambiguous" problem - * when call {@code anyOfSuccess} with empty arguments: {@code cffuFactory.anyOfSuccess()}. - */ - public Cffu anyOfSuccess() { - return new0(CompletableFutureUtils.anyOfSuccess()); - } - - //////////////////////////////////////////////////////////////////////////////// - //# Delay Execution, equivalent to same name static methods of CompletableFuture - // - // - delayedExecutor - //////////////////////////////////////////////////////////////////////////////// - - /** - * Returns a new Executor that submits a task to the default executor - * after the given delay (or no delay if non-positive). - * Each delay commences upon invocation of the returned executor's {@code execute} method. - * - * @param delay how long to delay, in units of {@code unit} - * @param unit a {@code TimeUnit} determining how to interpret the - * {@code delay} parameter - * @return the new delayed executor - */ - @Contract(pure = true) - public Executor delayedExecutor(long delay, TimeUnit unit) { - return CompletableFutureUtils.delayedExecutor(delay, unit, defaultExecutor); - } - - /** - * Returns a new Executor that submits a task to the given base executor - * after the given delay (or no delay if non-positive). - * Each delay commences upon invocation of the returned executor's {@code execute} method. - * - * @param delay how long to delay, in units of {@code unit} - * @param unit a {@code TimeUnit} determining how to interpret the - * {@code delay} parameter - * @param executor the base executor - * @return the new delayed executor - */ - @Contract(pure = true) - public Executor delayedExecutor(long delay, TimeUnit unit, Executor executor) { - return CompletableFutureUtils.delayedExecutor(delay, unit, executor); - } - - //////////////////////////////////////////////////////////////////////////////// - //# New allResultsOf* Factory Methods - //////////////////////////////////////////////////////////////////////////////// - /** * Returns a new Cffu with the results in the same order of all the given Cffus, * the new Cffu is completed when all the given Cffus complete. @@ -682,8 +547,108 @@ public Cffu> allResultsOfFastFail() { } //////////////////////////////////////////////////////////////////////////////// - //# New type-safe allTupleOf Factory Methods - // support 2~5 input arguments, method name prefix with `cffu` + //# anyOf* methods: + // + // - anyOf + // - anyOfSuccess + //////////////////////////////////////////////////////////////////////////////// + + /** + * Returns a new Cffu that is completed when any of the given Cffus complete, with the same result.
+ * Otherwise, if it completed exceptionally, the returned Cffu also does so, + * with a CompletionException holding this exception as its cause.
+ * If no Cffus are provided, returns an incomplete Cffu. + * + * @param cfs the Cffus + * @return a new Cffu that is completed with the result + * or exception from any of the given Cffus when one completes + * @throws NullPointerException if the array or any of its elements are {@code null} + * @see CompletableFuture#anyOf(CompletableFuture[]) + */ + @Contract(pure = true) + @SuppressWarnings("unchecked") + @SafeVarargs + public final Cffu anyOf(Cffu... cfs) { + return anyOf(toCompletableFutureArray((Cffu[]) cfs)); + } + + /** + * This method is the same as {@link #anyOf(Cffu[])} except with overloaded argument type {@link CompletableFuture}. + * + * @param cfs the CompletableFutures + * @return a new Cffu that is completed with the result + * or exception from any of the given CompletableFutures when one completes + * @throws NullPointerException if the array or any of its elements are {@code null} + * @see #anyOf(Cffu[]) + * @see CompletableFuture#anyOf(CompletableFuture[]) + */ + @Contract(pure = true) + @SuppressWarnings("unchecked") + @SafeVarargs + public final Cffu anyOf(CompletableFuture... cfs) { + return (Cffu) new0(CompletableFuture.anyOf(cfs)); + } + + /** + * Provided this overloaded method just for resolving "anyOf is ambiguous" problem + * when call {@code anyOf} with empty arguments: {@code cffuFactory.anyOf()}. + * + * @see #anyOf(Cffu[]) + * @see #anyOf(CompletableFuture[]) + */ + @Contract(pure = true) + public Cffu anyOf() { + return newIncompleteCffu(); + } + + /** + * Returns a new Cffu that is successful when any of the given Cffus success, + * with the same result. Otherwise, all the given Cffus complete exceptionally, + * the returned Cffu also does so, with a CompletionException holding + * an exception from any of the given Cffu as its cause. If no Cffu are provided, + * returns a new Cffu that is already completed exceptionally + * with a CompletionException holding a {@link NoCfsProvidedException} as its cause. + * + * @param cfs the Cffus + * @return a new Cffu + * @throws NullPointerException if the array or any of its elements are {@code null} + */ + @SuppressWarnings({"unchecked", "rawtypes"}) + @SafeVarargs + public final Cffu anyOfSuccess(Cffu... cfs) { + return (Cffu) anyOfSuccess(toCompletableFutureArray((Cffu[]) cfs)); + } + + /** + * Returns a new Cffu that is successful when any of the given CompletableFutures success, + * with the same result. Otherwise, all the given CompletableFutures complete exceptionally, + * the returned Cffu also does so, with a CompletionException holding + * an exception from any of the given CompletableFutures as its cause. If no CompletableFutures are provided, + * returns a new Cffu that is already completed exceptionally + * with a CompletionException holding a {@link NoCfsProvidedException} as its cause. + * + * @param cfs the CompletableFutures + * @return a new Cffu + * @throws NullPointerException if the array or any of its elements are {@code null} + */ + @SafeVarargs + public final Cffu anyOfSuccess(CompletableFuture... cfs) { + return new0(CompletableFutureUtils.anyOfSuccess(cfs)); + } + + /** + * Provided this overloaded method just for resolving "anyOfSuccess is ambiguous" problem + * when call {@code anyOfSuccess} with empty arguments: {@code cffuFactory.anyOfSuccess()}. + */ + public Cffu anyOfSuccess() { + return new0(CompletableFutureUtils.anyOfSuccess()); + } + + //////////////////////////////////////////////////////////////////////////////// + //# New type-safe allTupleOf Factory Methods, support 2~5 input arguments + // + // - allTupleOf + // - allTupleOfFastFail //////////////////////////////////////////////////////////////////////////////// /** @@ -1001,6 +966,43 @@ public Cffu> allTupleOfFastFail( return new0(CompletableFutureUtils.allTupleOfFastFail(cf1, cf2, cf3, cf4, cf5)); } + //////////////////////////////////////////////////////////////////////////////// + //# Delay Execution, equivalent to same name static methods of CompletableFuture + // + // - delayedExecutor + //////////////////////////////////////////////////////////////////////////////// + + /** + * Returns a new Executor that submits a task to the default executor + * after the given delay (or no delay if non-positive). + * Each delay commences upon invocation of the returned executor's {@code execute} method. + * + * @param delay how long to delay, in units of {@code unit} + * @param unit a {@code TimeUnit} determining how to interpret the + * {@code delay} parameter + * @return the new delayed executor + */ + @Contract(pure = true) + public Executor delayedExecutor(long delay, TimeUnit unit) { + return CompletableFutureUtils.delayedExecutor(delay, unit, defaultExecutor); + } + + /** + * Returns a new Executor that submits a task to the given base executor + * after the given delay (or no delay if non-positive). + * Each delay commences upon invocation of the returned executor's {@code execute} method. + * + * @param delay how long to delay, in units of {@code unit} + * @param unit a {@code TimeUnit} determining how to interpret the + * {@code delay} parameter + * @param executor the base executor + * @return the new delayed executor + */ + @Contract(pure = true) + public Executor delayedExecutor(long delay, TimeUnit unit, Executor executor) { + return CompletableFutureUtils.delayedExecutor(delay, unit, executor); + } + //////////////////////////////////////////////////////////////////////////////// //# Conversion (Static) Methods // diff --git a/cffu-core/src/main/java/io/foldright/cffu/CompletableFutureUtils.java b/cffu-core/src/main/java/io/foldright/cffu/CompletableFutureUtils.java index 5268d802..04aac6fe 100644 --- a/cffu-core/src/main/java/io/foldright/cffu/CompletableFutureUtils.java +++ b/cffu-core/src/main/java/io/foldright/cffu/CompletableFutureUtils.java @@ -243,6 +243,242 @@ public static CompletableFuture anyOfSuccess(CompletableFuture CompletableFuture> allTupleOf( + CompletableFuture cf1, CompletableFuture cf2) { + requireCfsAndEleNonNull(cf1, cf2); + + final Object[] result = new Object[2]; + return CompletableFuture.allOf( + cf1.thenAccept(t1 -> result[0] = t1), + cf2.thenAccept(t2 -> result[1] = t2) + ).thenApply(unused -> + Tuple2.of((T1) result[0], (T2) result[1]) + ); + } + + /** + * Returns a new CompletableFuture that is successful when the given two CompletableFutures success. + * If any of the given CompletableFutures complete exceptionally, then the returned + * CompletableFuture also does so *without* waiting other incomplete given CompletableFutures, + * with a CompletionException holding this exception as its cause. + *

+ * This method is the same as {@link #allTupleOf(CompletableFuture, CompletableFuture)} + * except for the fast-fail behavior. + * + * @return a new CompletableFuture that is successful when the given two CompletableFutures success + * @throws NullPointerException if any of the given CompletableFutures are {@code null} + * @see #allResultsOfFastFail(CompletableFuture[]) + * @see #allOfFastFail(CompletableFuture[]) + */ + @Contract(pure = true) + @SuppressWarnings("unchecked") + public static CompletableFuture> allTupleOfFastFail( + CompletableFuture cf1, CompletableFuture cf2) { + requireCfsAndEleNonNull(cf1, cf2); + + final Object[] result = new Object[2]; + return allOfFastFail( + cf1.thenAccept(t1 -> result[0] = t1), + cf2.thenAccept(t2 -> result[1] = t2) + ).thenApply(unused -> + Tuple2.of((T1) result[0], (T2) result[1]) + ); + } + + /** + * Returns a new CompletableFuture that is completed when the given three CompletableFutures complete. + * If any of the given CompletableFutures complete exceptionally, then the returned + * CompletableFuture also does so, with a CompletionException holding this exception as its cause. + * + * @return a new CompletableFuture that is completed when the given 3 CompletableFutures complete + * @throws NullPointerException if any of the given CompletableFutures are {@code null} + * @see #allResultsOf(CompletableFuture[]) + * @see CompletableFuture#allOf(CompletableFuture[]) + */ + @Contract(pure = true) + @SuppressWarnings("unchecked") + public static CompletableFuture> allTupleOf( + CompletableFuture cf1, CompletableFuture cf2, CompletableFuture cf3) { + requireCfsAndEleNonNull(cf1, cf2, cf3); + + final Object[] result = new Object[3]; + return CompletableFuture.allOf( + cf1.thenAccept(t1 -> result[0] = t1), + cf2.thenAccept(t2 -> result[1] = t2), + cf3.thenAccept(t3 -> result[2] = t3) + ).thenApply(unused -> + Tuple3.of((T1) result[0], (T2) result[1], (T3) result[2]) + ); + } + + /** + * Returns a new CompletableFuture that is successful when the given three CompletableFutures success. + * If any of the given CompletableFutures complete exceptionally, then the returned + * CompletableFuture also does so *without* waiting other incomplete given CompletableFutures, + * with a CompletionException holding this exception as its cause. + *

+ * This method is the same as {@link #allTupleOf(CompletableFuture, CompletableFuture, CompletableFuture)} + * except for the fast-fail behavior. + * + * @return a new CompletableFuture that is successful when the given three CompletableFutures success + * @throws NullPointerException if any of the given CompletableFutures are {@code null} + * @see #allResultsOfFastFail(CompletableFuture[]) + * @see #allOfFastFail(CompletableFuture[]) + */ + @Contract(pure = true) + @SuppressWarnings("unchecked") + public static CompletableFuture> allTupleOfFastFail( + CompletableFuture cf1, CompletableFuture cf2, CompletableFuture cf3) { + requireCfsAndEleNonNull(cf1, cf2, cf3); + + final Object[] result = new Object[3]; + return allOfFastFail( + cf1.thenAccept(t1 -> result[0] = t1), + cf2.thenAccept(t2 -> result[1] = t2), + cf3.thenAccept(t3 -> result[2] = t3) + ).thenApply(unused -> + Tuple3.of((T1) result[0], (T2) result[1], (T3) result[2]) + ); + } + + /** + * Returns a new CompletableFuture that is completed when the given 4 CompletableFutures complete. + * If any of the given CompletableFutures complete exceptionally, then the returned + * CompletableFuture also does so, with a CompletionException holding this exception as its cause. + * + * @return a new CompletableFuture that is completed when the given 4 CompletableFutures complete + * @throws NullPointerException if any of the given CompletableFutures are {@code null} + * @see #allResultsOf(CompletableFuture[]) + * @see CompletableFuture#allOf(CompletableFuture[]) + */ + @Contract(pure = true) + @SuppressWarnings("unchecked") + public static CompletableFuture> allTupleOf( + CompletableFuture cf1, CompletableFuture cf2, + CompletableFuture cf3, CompletableFuture cf4) { + requireCfsAndEleNonNull(cf1, cf2, cf3, cf4); + + final Object[] result = new Object[4]; + return CompletableFuture.allOf( + cf1.thenAccept(t1 -> result[0] = t1), + cf2.thenAccept(t2 -> result[1] = t2), + cf3.thenAccept(t3 -> result[2] = t3), + cf4.thenAccept(t4 -> result[3] = t4) + ).thenApply(unused -> + Tuple4.of((T1) result[0], (T2) result[1], (T3) result[2], (T4) result[3]) + ); + } + + /** + * Returns a new CompletableFuture that is successful when the given 4 CompletableFutures success. + * If any of the given CompletableFutures complete exceptionally, then the returned + * CompletableFuture also does so *without* waiting other incomplete given CompletableFutures, + * with a CompletionException holding this exception as its cause. + *

+ * This method is the same as {@link #allTupleOf(CompletableFuture, CompletableFuture, CompletableFuture, CompletableFuture)} + * except for the fast-fail behavior. + * + * @return a new CompletableFuture that is successful when the given 4 CompletableFutures success + * @throws NullPointerException if any of the given CompletableFutures are {@code null} + * @see #allResultsOfFastFail(CompletableFuture[]) + * @see #allOfFastFail(CompletableFuture[]) + */ + @Contract(pure = true) + @SuppressWarnings("unchecked") + public static CompletableFuture> allTupleOfFastFail( + CompletableFuture cf1, CompletableFuture cf2, + CompletableFuture cf3, CompletableFuture cf4) { + requireCfsAndEleNonNull(cf1, cf2, cf3, cf4); + + final Object[] result = new Object[4]; + return allOfFastFail( + cf1.thenAccept(t1 -> result[0] = t1), + cf2.thenAccept(t2 -> result[1] = t2), + cf3.thenAccept(t3 -> result[2] = t3), + cf4.thenAccept(t4 -> result[3] = t4) + ).thenApply(unused -> + Tuple4.of((T1) result[0], (T2) result[1], (T3) result[2], (T4) result[3]) + ); + } + + /** + * Returns a new CompletableFuture that is completed when the given 5 CompletableFutures complete. + * If any of the given CompletableFutures complete exceptionally, then the returned + * CompletableFuture also does so, with a CompletionException holding this exception as its cause. + * + * @return a new CompletableFuture that is completed when the given 5 CompletableFutures complete + * @throws NullPointerException if any of the given CompletableFutures are {@code null} + * @see #allResultsOf(CompletableFuture[]) + * @see CompletableFuture#allOf(CompletableFuture[]) + */ + @Contract(pure = true) + @SuppressWarnings("unchecked") + public static CompletableFuture> allTupleOf( + CompletableFuture cf1, CompletableFuture cf2, + CompletableFuture cf3, CompletableFuture cf4, CompletableFuture cf5) { + requireCfsAndEleNonNull(cf1, cf2, cf3, cf4, cf5); + + final Object[] result = new Object[5]; + return CompletableFuture.allOf( + cf1.thenAccept(t1 -> result[0] = t1), + cf2.thenAccept(t2 -> result[1] = t2), + cf3.thenAccept(t3 -> result[2] = t3), + cf4.thenAccept(t4 -> result[3] = t4), + cf5.thenAccept(t5 -> result[4] = t5) + ).thenApply(unused -> + Tuple5.of((T1) result[0], (T2) result[1], (T3) result[2], (T4) result[3], (T5) result[4]) + ); + } + + /** + * Returns a new CompletableFuture that is successful when the given 5 CompletableFutures success. + * If any of the given CompletableFutures complete exceptionally, then the returned + * CompletableFuture also does so *without* waiting other incomplete given CompletableFutures, + * with a CompletionException holding this exception as its cause. + *

+ * This method is the same as {@link #allTupleOf(CompletableFuture, CompletableFuture, CompletableFuture, CompletableFuture, CompletableFuture)} + * except for the fast-fail behavior. + * + * @return a new CompletableFuture that is successful when the given 5 CompletableFutures success + * @throws NullPointerException if any of the given CompletableFutures are {@code null} + * @see #allResultsOfFastFail(CompletableFuture[]) + * @see #allOfFastFail(CompletableFuture[]) + */ + @Contract(pure = true) + @SuppressWarnings("unchecked") + public static CompletableFuture> allTupleOfFastFail( + CompletableFuture cf1, CompletableFuture cf2, + CompletableFuture cf3, CompletableFuture cf4, CompletableFuture cf5) { + requireCfsAndEleNonNull(cf1, cf2, cf3, cf4, cf5); + + final Object[] result = new Object[5]; + return allOfFastFail( + cf1.thenAccept(t1 -> result[0] = t1), + cf2.thenAccept(t2 -> result[1] = t2), + cf3.thenAccept(t3 -> result[2] = t3), + cf4.thenAccept(t4 -> result[3] = t4), + cf5.thenAccept(t5 -> result[4] = t5) + ).thenApply(unused -> + Tuple5.of((T1) result[0], (T2) result[1], (T3) result[2], (T4) result[3], (T5) result[4]) + ); + } + //////////////////////////////////////////////////////////////////////////////// //# `then both(binary input)` methods with fast-fail support: // @@ -493,242 +729,6 @@ public static CompletableFuture thenCombineFastFailAsync( ).thenApplyAsync(unused -> fn.apply((T) result[0], (U) result[1]), executor); } - //////////////////////////////////////////////////////////////////////////////// - //# allTupleOf/allTupleOfFastFail methods - //////////////////////////////////////////////////////////////////////////////// - - /** - * Returns a new CompletableFuture that is completed when the given two CompletableFutures complete. - * If any of the given CompletableFutures complete exceptionally, then the returned - * CompletableFuture also does so, with a CompletionException holding this exception as its cause. - * - * @return a new CompletableFuture that is completed when the given 2 CompletableFutures complete - * @throws NullPointerException if any of the given CompletableFutures are {@code null} - * @see #allResultsOf(CompletableFuture[]) - * @see CompletableFuture#allOf(CompletableFuture[]) - */ - @Contract(pure = true) - @SuppressWarnings("unchecked") - public static CompletableFuture> allTupleOf( - CompletableFuture cf1, CompletableFuture cf2) { - requireCfsAndEleNonNull(cf1, cf2); - - final Object[] result = new Object[2]; - return CompletableFuture.allOf( - cf1.thenAccept(t1 -> result[0] = t1), - cf2.thenAccept(t2 -> result[1] = t2) - ).thenApply(unused -> - Tuple2.of((T1) result[0], (T2) result[1]) - ); - } - - /** - * Returns a new CompletableFuture that is successful when the given two CompletableFutures success. - * If any of the given CompletableFutures complete exceptionally, then the returned - * CompletableFuture also does so *without* waiting other incomplete given CompletableFutures, - * with a CompletionException holding this exception as its cause. - *

- * This method is the same as {@link #allTupleOf(CompletableFuture, CompletableFuture)} - * except for the fast-fail behavior. - * - * @return a new CompletableFuture that is successful when the given two CompletableFutures success - * @throws NullPointerException if any of the given CompletableFutures are {@code null} - * @see #allResultsOfFastFail(CompletableFuture[]) - * @see #allOfFastFail(CompletableFuture[]) - */ - @Contract(pure = true) - @SuppressWarnings("unchecked") - public static CompletableFuture> allTupleOfFastFail( - CompletableFuture cf1, CompletableFuture cf2) { - requireCfsAndEleNonNull(cf1, cf2); - - final Object[] result = new Object[2]; - return allOfFastFail( - cf1.thenAccept(t1 -> result[0] = t1), - cf2.thenAccept(t2 -> result[1] = t2) - ).thenApply(unused -> - Tuple2.of((T1) result[0], (T2) result[1]) - ); - } - - /** - * Returns a new CompletableFuture that is completed when the given three CompletableFutures complete. - * If any of the given CompletableFutures complete exceptionally, then the returned - * CompletableFuture also does so, with a CompletionException holding this exception as its cause. - * - * @return a new CompletableFuture that is completed when the given 3 CompletableFutures complete - * @throws NullPointerException if any of the given CompletableFutures are {@code null} - * @see #allResultsOf(CompletableFuture[]) - * @see CompletableFuture#allOf(CompletableFuture[]) - */ - @Contract(pure = true) - @SuppressWarnings("unchecked") - public static CompletableFuture> allTupleOf( - CompletableFuture cf1, CompletableFuture cf2, CompletableFuture cf3) { - requireCfsAndEleNonNull(cf1, cf2, cf3); - - final Object[] result = new Object[3]; - return CompletableFuture.allOf( - cf1.thenAccept(t1 -> result[0] = t1), - cf2.thenAccept(t2 -> result[1] = t2), - cf3.thenAccept(t3 -> result[2] = t3) - ).thenApply(unused -> - Tuple3.of((T1) result[0], (T2) result[1], (T3) result[2]) - ); - } - - /** - * Returns a new CompletableFuture that is successful when the given three CompletableFutures success. - * If any of the given CompletableFutures complete exceptionally, then the returned - * CompletableFuture also does so *without* waiting other incomplete given CompletableFutures, - * with a CompletionException holding this exception as its cause. - *

- * This method is the same as {@link #allTupleOf(CompletableFuture, CompletableFuture, CompletableFuture)} - * except for the fast-fail behavior. - * - * @return a new CompletableFuture that is successful when the given three CompletableFutures success - * @throws NullPointerException if any of the given CompletableFutures are {@code null} - * @see #allResultsOfFastFail(CompletableFuture[]) - * @see #allOfFastFail(CompletableFuture[]) - */ - @Contract(pure = true) - @SuppressWarnings("unchecked") - public static CompletableFuture> allTupleOfFastFail( - CompletableFuture cf1, CompletableFuture cf2, CompletableFuture cf3) { - requireCfsAndEleNonNull(cf1, cf2, cf3); - - final Object[] result = new Object[3]; - return allOfFastFail( - cf1.thenAccept(t1 -> result[0] = t1), - cf2.thenAccept(t2 -> result[1] = t2), - cf3.thenAccept(t3 -> result[2] = t3) - ).thenApply(unused -> - Tuple3.of((T1) result[0], (T2) result[1], (T3) result[2]) - ); - } - - /** - * Returns a new CompletableFuture that is completed when the given 4 CompletableFutures complete. - * If any of the given CompletableFutures complete exceptionally, then the returned - * CompletableFuture also does so, with a CompletionException holding this exception as its cause. - * - * @return a new CompletableFuture that is completed when the given 4 CompletableFutures complete - * @throws NullPointerException if any of the given CompletableFutures are {@code null} - * @see #allResultsOf(CompletableFuture[]) - * @see CompletableFuture#allOf(CompletableFuture[]) - */ - @Contract(pure = true) - @SuppressWarnings("unchecked") - public static CompletableFuture> allTupleOf( - CompletableFuture cf1, CompletableFuture cf2, - CompletableFuture cf3, CompletableFuture cf4) { - requireCfsAndEleNonNull(cf1, cf2, cf3, cf4); - - final Object[] result = new Object[4]; - return CompletableFuture.allOf( - cf1.thenAccept(t1 -> result[0] = t1), - cf2.thenAccept(t2 -> result[1] = t2), - cf3.thenAccept(t3 -> result[2] = t3), - cf4.thenAccept(t4 -> result[3] = t4) - ).thenApply(unused -> - Tuple4.of((T1) result[0], (T2) result[1], (T3) result[2], (T4) result[3]) - ); - } - - /** - * Returns a new CompletableFuture that is successful when the given 4 CompletableFutures success. - * If any of the given CompletableFutures complete exceptionally, then the returned - * CompletableFuture also does so *without* waiting other incomplete given CompletableFutures, - * with a CompletionException holding this exception as its cause. - *

- * This method is the same as {@link #allTupleOf(CompletableFuture, CompletableFuture, CompletableFuture, CompletableFuture)} - * except for the fast-fail behavior. - * - * @return a new CompletableFuture that is successful when the given 4 CompletableFutures success - * @throws NullPointerException if any of the given CompletableFutures are {@code null} - * @see #allResultsOfFastFail(CompletableFuture[]) - * @see #allOfFastFail(CompletableFuture[]) - */ - @Contract(pure = true) - @SuppressWarnings("unchecked") - public static CompletableFuture> allTupleOfFastFail( - CompletableFuture cf1, CompletableFuture cf2, - CompletableFuture cf3, CompletableFuture cf4) { - requireCfsAndEleNonNull(cf1, cf2, cf3, cf4); - - final Object[] result = new Object[4]; - return allOfFastFail( - cf1.thenAccept(t1 -> result[0] = t1), - cf2.thenAccept(t2 -> result[1] = t2), - cf3.thenAccept(t3 -> result[2] = t3), - cf4.thenAccept(t4 -> result[3] = t4) - ).thenApply(unused -> - Tuple4.of((T1) result[0], (T2) result[1], (T3) result[2], (T4) result[3]) - ); - } - - /** - * Returns a new CompletableFuture that is completed when the given 5 CompletableFutures complete. - * If any of the given CompletableFutures complete exceptionally, then the returned - * CompletableFuture also does so, with a CompletionException holding this exception as its cause. - * - * @return a new CompletableFuture that is completed when the given 5 CompletableFutures complete - * @throws NullPointerException if any of the given CompletableFutures are {@code null} - * @see #allResultsOf(CompletableFuture[]) - * @see CompletableFuture#allOf(CompletableFuture[]) - */ - @Contract(pure = true) - @SuppressWarnings("unchecked") - public static CompletableFuture> allTupleOf( - CompletableFuture cf1, CompletableFuture cf2, - CompletableFuture cf3, CompletableFuture cf4, CompletableFuture cf5) { - requireCfsAndEleNonNull(cf1, cf2, cf3, cf4, cf5); - - final Object[] result = new Object[5]; - return CompletableFuture.allOf( - cf1.thenAccept(t1 -> result[0] = t1), - cf2.thenAccept(t2 -> result[1] = t2), - cf3.thenAccept(t3 -> result[2] = t3), - cf4.thenAccept(t4 -> result[3] = t4), - cf5.thenAccept(t5 -> result[4] = t5) - ).thenApply(unused -> - Tuple5.of((T1) result[0], (T2) result[1], (T3) result[2], (T4) result[3], (T5) result[4]) - ); - } - - /** - * Returns a new CompletableFuture that is successful when the given 5 CompletableFutures success. - * If any of the given CompletableFutures complete exceptionally, then the returned - * CompletableFuture also does so *without* waiting other incomplete given CompletableFutures, - * with a CompletionException holding this exception as its cause. - *

- * This method is the same as {@link #allTupleOf(CompletableFuture, CompletableFuture, CompletableFuture, CompletableFuture, CompletableFuture)} - * except for the fast-fail behavior. - * - * @return a new CompletableFuture that is successful when the given 5 CompletableFutures success - * @throws NullPointerException if any of the given CompletableFutures are {@code null} - * @see #allResultsOfFastFail(CompletableFuture[]) - * @see #allOfFastFail(CompletableFuture[]) - */ - @Contract(pure = true) - @SuppressWarnings("unchecked") - public static CompletableFuture> allTupleOfFastFail( - CompletableFuture cf1, CompletableFuture cf2, - CompletableFuture cf3, CompletableFuture cf4, CompletableFuture cf5) { - requireCfsAndEleNonNull(cf1, cf2, cf3, cf4, cf5); - - final Object[] result = new Object[5]; - return allOfFastFail( - cf1.thenAccept(t1 -> result[0] = t1), - cf2.thenAccept(t2 -> result[1] = t2), - cf3.thenAccept(t3 -> result[2] = t3), - cf4.thenAccept(t4 -> result[3] = t4), - cf5.thenAccept(t5 -> result[4] = t5) - ).thenApply(unused -> - Tuple5.of((T1) result[0], (T2) result[1], (T3) result[2], (T4) result[3], (T5) result[4]) - ); - } - //////////////////////////////////////////////////////////////////////////////// //# `then either(binary input)` methods with either(any)-success support: // @@ -929,7 +929,7 @@ public static CompletableFuture applyToEitherSuccessAsync( } //////////////////////////////////////////////////////////////////////////////// - //# More new enhanced methods + //# New enhanced methods //////////////////////////////////////////////////////////////////////////////// /** diff --git a/cffu-core/src/test/java/io/foldright/cffu/CompletableFutureUtilsTest.java b/cffu-core/src/test/java/io/foldright/cffu/CompletableFutureUtilsTest.java index 5c4655d2..e57614e9 100644 --- a/cffu-core/src/test/java/io/foldright/cffu/CompletableFutureUtilsTest.java +++ b/cffu-core/src/test/java/io/foldright/cffu/CompletableFutureUtilsTest.java @@ -517,102 +517,6 @@ void test_anyOf__concurrent() throws Exception { ).get()); } - //////////////////////////////////////////////////////////////////////////////// - //# both methods - //////////////////////////////////////////////////////////////////////////////// - - @Test - void test_both() throws Exception { - final CompletableFuture cf_n = completedFuture(n); - final CompletableFuture cf_nn = completedFuture(n + n); - - final Runnable runnable = () -> { - }; - assertNull(runAfterBothFastFail(cf_n, cf_nn, runnable).get()); - assertNull(runAfterBothFastFailAsync(cf_n, cf_nn, runnable).get()); - assertNull(runAfterBothFastFailAsync(cf_n, cf_nn, runnable, executorService).get()); - - BiConsumer bc = (i1, i2) -> { - }; - assertNull(thenAcceptBothFastFail(cf_n, cf_nn, bc).get()); - assertNull(thenAcceptBothFastFailAsync(cf_n, cf_nn, bc).get()); - assertNull(thenAcceptBothFastFailAsync(cf_n, cf_nn, bc, executorService).get()); - - assertEquals(3 * n, thenCombineFastFail(cf_n, cf_nn, Integer::sum).get()); - assertEquals(3 * n, thenCombineFastFailAsync(cf_n, cf_nn, Integer::sum).get()); - assertEquals(3 * n, thenCombineFastFailAsync(cf_n, cf_nn, Integer::sum, executorService).get()); - } - - @Test - void both_fastFail() throws Exception { - CompletableFuture cf_n = CompletableFuture.supplyAsync(() -> { - sleep(2_000); - return n; - }); - final CompletableFuture failed = failedFuture(rte); - - final Runnable runnable = () -> { - }; - try { - runAfterBothFastFail(cf_n, failed, runnable).get(1, TimeUnit.MILLISECONDS); - fail(); - } catch (ExecutionException expected) { - assertSame(rte, expected.getCause()); - } - try { - runAfterBothFastFailAsync(cf_n, failed, runnable).get(1, TimeUnit.MILLISECONDS); - fail(); - } catch (ExecutionException expected) { - assertSame(rte, expected.getCause()); - } - try { - runAfterBothFastFailAsync(cf_n, failed, runnable, executorService).get(1, TimeUnit.MILLISECONDS); - fail(); - } catch (ExecutionException expected) { - assertSame(rte, expected.getCause()); - } - - BiConsumer bc = (i1, i2) -> { - }; - try { - thenAcceptBothFastFail(cf_n, failed, bc).get(1, TimeUnit.MILLISECONDS); - fail(); - } catch (ExecutionException expected) { - assertSame(rte, expected.getCause()); - } - try { - thenAcceptBothFastFailAsync(cf_n, failed, bc).get(1, TimeUnit.MILLISECONDS); - fail(); - } catch (ExecutionException expected) { - assertSame(rte, expected.getCause()); - } - try { - thenAcceptBothFastFailAsync(cf_n, failed, bc, executorService).get(1, TimeUnit.MILLISECONDS); - fail(); - } catch (ExecutionException expected) { - assertSame(rte, expected.getCause()); - } - - try { - thenCombineFastFail(cf_n, failed, Integer::sum).get(1, TimeUnit.MILLISECONDS); - fail(); - } catch (ExecutionException expected) { - assertSame(rte, expected.getCause()); - } - try { - thenCombineFastFailAsync(cf_n, failed, Integer::sum).get(1, TimeUnit.MILLISECONDS); - fail(); - } catch (ExecutionException expected) { - assertSame(rte, expected.getCause()); - } - try { - thenCombineFastFailAsync(cf_n, failed, Integer::sum, executorService).get(1, TimeUnit.MILLISECONDS); - fail(); - } catch (ExecutionException expected) { - assertSame(rte, expected.getCause()); - } - } - //////////////////////////////////////////////////////////////////////////////// //# allTupleOf methods //////////////////////////////////////////////////////////////////////////////// @@ -740,6 +644,102 @@ void test_allTupleOf_NotFastFail() throws Exception { } } + //////////////////////////////////////////////////////////////////////////////// + //# both methods + //////////////////////////////////////////////////////////////////////////////// + + @Test + void test_both() throws Exception { + final CompletableFuture cf_n = completedFuture(n); + final CompletableFuture cf_nn = completedFuture(n + n); + + final Runnable runnable = () -> { + }; + assertNull(runAfterBothFastFail(cf_n, cf_nn, runnable).get()); + assertNull(runAfterBothFastFailAsync(cf_n, cf_nn, runnable).get()); + assertNull(runAfterBothFastFailAsync(cf_n, cf_nn, runnable, executorService).get()); + + BiConsumer bc = (i1, i2) -> { + }; + assertNull(thenAcceptBothFastFail(cf_n, cf_nn, bc).get()); + assertNull(thenAcceptBothFastFailAsync(cf_n, cf_nn, bc).get()); + assertNull(thenAcceptBothFastFailAsync(cf_n, cf_nn, bc, executorService).get()); + + assertEquals(3 * n, thenCombineFastFail(cf_n, cf_nn, Integer::sum).get()); + assertEquals(3 * n, thenCombineFastFailAsync(cf_n, cf_nn, Integer::sum).get()); + assertEquals(3 * n, thenCombineFastFailAsync(cf_n, cf_nn, Integer::sum, executorService).get()); + } + + @Test + void both_fastFail() throws Exception { + CompletableFuture cf_n = CompletableFuture.supplyAsync(() -> { + sleep(2_000); + return n; + }); + final CompletableFuture failed = failedFuture(rte); + + final Runnable runnable = () -> { + }; + try { + runAfterBothFastFail(cf_n, failed, runnable).get(1, TimeUnit.MILLISECONDS); + fail(); + } catch (ExecutionException expected) { + assertSame(rte, expected.getCause()); + } + try { + runAfterBothFastFailAsync(cf_n, failed, runnable).get(1, TimeUnit.MILLISECONDS); + fail(); + } catch (ExecutionException expected) { + assertSame(rte, expected.getCause()); + } + try { + runAfterBothFastFailAsync(cf_n, failed, runnable, executorService).get(1, TimeUnit.MILLISECONDS); + fail(); + } catch (ExecutionException expected) { + assertSame(rte, expected.getCause()); + } + + BiConsumer bc = (i1, i2) -> { + }; + try { + thenAcceptBothFastFail(cf_n, failed, bc).get(1, TimeUnit.MILLISECONDS); + fail(); + } catch (ExecutionException expected) { + assertSame(rte, expected.getCause()); + } + try { + thenAcceptBothFastFailAsync(cf_n, failed, bc).get(1, TimeUnit.MILLISECONDS); + fail(); + } catch (ExecutionException expected) { + assertSame(rte, expected.getCause()); + } + try { + thenAcceptBothFastFailAsync(cf_n, failed, bc, executorService).get(1, TimeUnit.MILLISECONDS); + fail(); + } catch (ExecutionException expected) { + assertSame(rte, expected.getCause()); + } + + try { + thenCombineFastFail(cf_n, failed, Integer::sum).get(1, TimeUnit.MILLISECONDS); + fail(); + } catch (ExecutionException expected) { + assertSame(rte, expected.getCause()); + } + try { + thenCombineFastFailAsync(cf_n, failed, Integer::sum).get(1, TimeUnit.MILLISECONDS); + fail(); + } catch (ExecutionException expected) { + assertSame(rte, expected.getCause()); + } + try { + thenCombineFastFailAsync(cf_n, failed, Integer::sum, executorService).get(1, TimeUnit.MILLISECONDS); + fail(); + } catch (ExecutionException expected) { + assertSame(rte, expected.getCause()); + } + } + //////////////////////////////////////////////////////////////////////////////// //# either methods //////////////////////////////////////////////////////////////////////////////// @@ -789,7 +789,7 @@ void test_either_success() throws Exception { } //////////////////////////////////////////////////////////////////////////////// - //# More new enhanced methods + //# New enhanced methods //////////////////////////////////////////////////////////////////////////////// @Test diff --git a/cffu-core/src/test/java/io/foldright/cffu/tuple/TupleTest.kt b/cffu-core/src/test/java/io/foldright/cffu/tuple/TupleTest.kt index f3783e74..2e144c28 100644 --- a/cffu-core/src/test/java/io/foldright/cffu/tuple/TupleTest.kt +++ b/cffu-core/src/test/java/io/foldright/cffu/tuple/TupleTest.kt @@ -18,8 +18,14 @@ class TupleTest : FunSpec({ val tuple2 = Tuple2.of(e1, e2) tuple2._1 shouldBe e1 tuple2._2 shouldBe e2 + tuple2 shouldBe Tuple2.of(e1, e2) + tuple2 shouldBe tuple2 + tuple2 shouldNotBe Tuple2.of(e1, e2 + "X") + tuple2 shouldNotBe null + tuple2 shouldNotBe "foo" + mapOf(tuple2 to value, pair2)[tuple2] shouldBe value tuple2.toString() shouldBe "Tuple2(1, 2)" } @@ -29,8 +35,14 @@ class TupleTest : FunSpec({ tuple3._1 shouldBe e1 tuple3._2 shouldBe e2 tuple3._3 shouldBe e3 + tuple3 shouldBe Tuple3.of(e1, e2, e3) + tuple3 shouldBe tuple3 + tuple3 shouldNotBe Tuple3.of(e1, e2, e3 + 1.0) + tuple3 shouldNotBe null + tuple3 shouldNotBe "foo" + mapOf(tuple3 to value, pair2)[tuple3] shouldBe value tuple3.toString() shouldBe "Tuple3(1, 2, 3.14)" } @@ -41,8 +53,14 @@ class TupleTest : FunSpec({ tuple4._2 shouldBe e2 tuple4._3 shouldBe e3 tuple4._4 shouldBe e4 + tuple4 shouldBe Tuple4.of(e1, e2, e3, e4) + tuple4 shouldBe tuple4 + tuple4 shouldNotBe Tuple4.of(e1, e2, e3, e4 + 1) + tuple4 shouldNotBe null + tuple4 shouldNotBe "foo" + mapOf(tuple4 to value, pair2)[tuple4] shouldBe value tuple4.toString() shouldBe "Tuple4(1, 2, 3.14, 4)" } @@ -54,8 +72,14 @@ class TupleTest : FunSpec({ tuple5._3 shouldBe e3 tuple5._4 shouldBe e4 tuple5._5 shouldBe e5 + tuple5 shouldBe Tuple5.of(e1, e2, e3, e4, e5) + tuple5 shouldBe tuple5 + tuple5 shouldNotBe Tuple5.of(e1, e2, e3, e4, '6') + tuple5 shouldNotBe null + tuple5 shouldNotBe "foo" + mapOf(tuple5 to value, pair2)[tuple5] shouldBe value tuple5.toString() shouldBe "Tuple5(1, 2, 3.14, 4, 5)" } diff --git a/cffu-kotlin/src/main/java/io/foldright/cffu/kotlin/CompletableFutureExtensions.kt b/cffu-kotlin/src/main/java/io/foldright/cffu/kotlin/CompletableFutureExtensions.kt index fcdb2841..aa8ed1f2 100644 --- a/cffu-kotlin/src/main/java/io/foldright/cffu/kotlin/CompletableFutureExtensions.kt +++ b/cffu-kotlin/src/main/java/io/foldright/cffu/kotlin/CompletableFutureExtensions.kt @@ -22,52 +22,12 @@ import java.util.function.Function //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////// -//# allOf* methods +//# allOf* methods for Array/Collection // -// - allResultsOfCompletableFuture -// - allOfCompletableFuture -// - allResultsOfFastFailCompletableFuture -// - allOfFastFailCompletableFuture +// - allOfCompletableFuture / allOfFastFailCompletableFuture +// - allResultsOfCompletableFuture / allResultsOfFastFailCompletableFuture //////////////////////////////////////// -/** - * Returns a new CompletableFuture with the results in the **same order** of all the given - * CompletableFutures, the returned new CompletableFuture is completed when all the given CompletableFutures complete. - * If any of the given CompletableFutures complete exceptionally, then the returned CompletableFuture - * also does so, with a CompletionException holding this exception as its cause. - * If no CompletableFutures are provided, returns a CompletableFuture completed with the value empty list. - * - * This method is the same as [allOfCompletableFuture], - * except the returned CompletableFuture contains the results of input CompletableFutures. - * - * This method is the same as [CompletableFutureUtils.allResultsOf], - * providing this method is convenient for method chaining. - * - * @see allResultsOfCffu - * @see allOfCompletableFuture - */ -fun Collection>.allResultsOfCompletableFuture(): CompletableFuture> = - CompletableFutureUtils.allResultsOf(*this.toTypedArray()) - -/** - * Returns a new CompletableFuture with the results in the **same order** of all the given - * CompletableFutures, the returned new CompletableFuture is completed when all the given CompletableFutures complete. - * If any of the given CompletableFutures complete exceptionally, then the returned CompletableFuture - * also does so, with a CompletionException holding this exception as its cause. - * If no CompletableFutures are provided, returns a CompletableFuture completed with the value empty list. - * - * This method is the same as [allOfCompletableFuture], - * except the returned CompletableFuture contains the results of input CompletableFutures. - * - * This method is the same as [CompletableFutureUtils.allResultsOf], - * providing this method is convenient for method chaining. - * - * @see allResultsOfCffu - * @see allOfCompletableFuture - */ -fun Array>.allResultsOfCompletableFuture(): CompletableFuture> = - CompletableFutureUtils.allResultsOf(*this) - /** * Returns a new CompletableFuture that is completed when all the given CompletableFutures complete. * If any of the given CompletableFutures complete exceptionally, then the returned CompletableFuture @@ -113,84 +73,122 @@ fun Array>.allOfCompletableFuture(): CompletableFuture< CompletableFuture.allOf(*this) /** - * Returns a new CompletableFuture with the results in the **same order** of all the given - * CompletableFutures, the new CompletableFuture success when all the given CompletableFutures success. + * Returns a new CompletableFuture that is successful when all the given CompletableFutures success, + * the results(`CompletableFuture`) of the given CompletableFutures are not reflected in the returned CompletableFuture, + * but may be obtained by inspecting them individually. * If any of the given CompletableFutures complete exceptionally, then the returned CompletableFuture * also does so *without* waiting other incomplete given CompletableFutures, * with a CompletionException holding this exception as its cause. + * If no CompletableFutures are provided, returns a CompletableFuture completed with the value `null`. + * + * This method is the same as [CompletableFutureUtils.allOfFastFail], + * providing this method is convenient for method chaining. + * + * @see allResultsOfFastFailCffu + * @see allOfFastFailCffu + * @see allResultsOfFastFailCompletableFuture + * @see CompletableFutureUtils.allOfFastFail + */ +fun Collection>.allOfFastFailCompletableFuture(): CompletableFuture = + CompletableFutureUtils.allOfFastFail(*this.toTypedArray()) + +/** + * Returns a new CompletableFuture that is successful when all the given CompletableFutures success, + * the results(`CompletableFuture`) of the given CompletableFutures are not reflected in the returned CompletableFuture, + * but may be obtained by inspecting them individually. + * If any of the given CompletableFutures complete exceptionally, then the returned CompletableFuture + * also does so *without* waiting other incomplete given CompletableFutures, + * with a CompletionException holding this exception as its cause. + * If no CompletableFutures are provided, returns a CompletableFuture completed with the value `null`. + * + * This method is the same as [CompletableFutureUtils.allOfFastFail], + * providing this method is convenient for method chaining. + * + * @see allResultsOfFastFailCffu + * @see allOfFastFailCffu + * @see allResultsOfFastFailCompletableFuture + * @see CompletableFutureUtils.allOfFastFail + */ +fun Array>.allOfFastFailCompletableFuture(): CompletableFuture = + CompletableFutureUtils.allOfFastFail(*this) + +/** + * Returns a new CompletableFuture with the results in the **same order** of all the given + * CompletableFutures, the returned new CompletableFuture is completed when all the given CompletableFutures complete. + * If any of the given CompletableFutures complete exceptionally, then the returned CompletableFuture + * also does so, with a CompletionException holding this exception as its cause. * If no CompletableFutures are provided, returns a CompletableFuture completed with the value empty list. * - * This method is the same as [allOfFastFailCompletableFuture], + * This method is the same as [allOfCompletableFuture], * except the returned CompletableFuture contains the results of input CompletableFutures. * - * This method is the same as [CompletableFutureUtils.allResultsOfFastFail], + * This method is the same as [CompletableFutureUtils.allResultsOf], * providing this method is convenient for method chaining. * - * @see allResultsOfFastFailCffu - * @see allOfFastFailCompletableFuture + * @see allResultsOfCffu + * @see allOfCompletableFuture */ -fun Collection>.allResultsOfFastFailCompletableFuture(): CompletableFuture> = - CompletableFutureUtils.allResultsOfFastFail(*this.toTypedArray()) +fun Collection>.allResultsOfCompletableFuture(): CompletableFuture> = + CompletableFutureUtils.allResultsOf(*this.toTypedArray()) /** * Returns a new CompletableFuture with the results in the **same order** of all the given - * CompletableFutures, the new CompletableFuture success when all the given CompletableFutures success. + * CompletableFutures, the returned new CompletableFuture is completed when all the given CompletableFutures complete. * If any of the given CompletableFutures complete exceptionally, then the returned CompletableFuture - * also does so *without* waiting other incomplete given CompletableFutures, - * with a CompletionException holding this exception as its cause. + * also does so, with a CompletionException holding this exception as its cause. * If no CompletableFutures are provided, returns a CompletableFuture completed with the value empty list. * - * This method is the same as [allOfFastFailCompletableFuture], + * This method is the same as [allOfCompletableFuture], * except the returned CompletableFuture contains the results of input CompletableFutures. * - * This method is the same as [CompletableFutureUtils.allResultsOfFastFail], + * This method is the same as [CompletableFutureUtils.allResultsOf], * providing this method is convenient for method chaining. * - * @see allResultsOfFastFailCffu - * @see allOfFastFailCompletableFuture + * @see allResultsOfCffu + * @see allOfCompletableFuture */ -fun Array>.allResultsOfFastFailCompletableFuture(): CompletableFuture> = - CompletableFutureUtils.allResultsOfFastFail(*this) +fun Array>.allResultsOfCompletableFuture(): CompletableFuture> = + CompletableFutureUtils.allResultsOf(*this) /** - * Returns a new CompletableFuture that is successful when all the given CompletableFutures success, - * the results(`CompletableFuture`) of the given CompletableFutures are not reflected in the returned CompletableFuture, - * but may be obtained by inspecting them individually. + * Returns a new CompletableFuture with the results in the **same order** of all the given + * CompletableFutures, the new CompletableFuture success when all the given CompletableFutures success. * If any of the given CompletableFutures complete exceptionally, then the returned CompletableFuture * also does so *without* waiting other incomplete given CompletableFutures, * with a CompletionException holding this exception as its cause. - * If no CompletableFutures are provided, returns a CompletableFuture completed with the value `null`. + * If no CompletableFutures are provided, returns a CompletableFuture completed with the value empty list. * - * This method is the same as [CompletableFutureUtils.allOfFastFail], + * This method is the same as [allOfFastFailCompletableFuture], + * except the returned CompletableFuture contains the results of input CompletableFutures. + * + * This method is the same as [CompletableFutureUtils.allResultsOfFastFail], * providing this method is convenient for method chaining. * * @see allResultsOfFastFailCffu - * @see allOfFastFailCffu - * @see allResultsOfFastFailCompletableFuture - * @see CompletableFutureUtils.allOfFastFail + * @see allOfFastFailCompletableFuture */ -fun Collection>.allOfFastFailCompletableFuture(): CompletableFuture = - CompletableFutureUtils.allOfFastFail(*this.toTypedArray()) +fun Collection>.allResultsOfFastFailCompletableFuture(): CompletableFuture> = + CompletableFutureUtils.allResultsOfFastFail(*this.toTypedArray()) /** - * Returns a new CompletableFuture that is successful when all the given CompletableFutures success, - * the results(`CompletableFuture`) of the given CompletableFutures are not reflected in the returned CompletableFuture, - * but may be obtained by inspecting them individually. + * Returns a new CompletableFuture with the results in the **same order** of all the given + * CompletableFutures, the new CompletableFuture success when all the given CompletableFutures success. * If any of the given CompletableFutures complete exceptionally, then the returned CompletableFuture * also does so *without* waiting other incomplete given CompletableFutures, * with a CompletionException holding this exception as its cause. - * If no CompletableFutures are provided, returns a CompletableFuture completed with the value `null`. + * If no CompletableFutures are provided, returns a CompletableFuture completed with the value empty list. * - * This method is the same as [CompletableFutureUtils.allOfFastFail], + * This method is the same as [allOfFastFailCompletableFuture], + * except the returned CompletableFuture contains the results of input CompletableFutures. + * + * This method is the same as [CompletableFutureUtils.allResultsOfFastFail], * providing this method is convenient for method chaining. * * @see allResultsOfFastFailCffu - * @see allOfFastFailCffu - * @see allResultsOfFastFailCompletableFuture - * @see CompletableFutureUtils.allOfFastFail + * @see allOfFastFailCompletableFuture */ -fun Array>.allOfFastFailCompletableFuture(): CompletableFuture = - CompletableFutureUtils.allOfFastFail(*this) +fun Array>.allResultsOfFastFailCompletableFuture(): CompletableFuture> = + CompletableFutureUtils.allResultsOfFastFail(*this) //////////////////////////////////////// //# anyOf* methods @@ -261,140 +259,6 @@ fun Collection>.anyOfSuccessCompletableFuture(): Co fun Array>.anyOfSuccessCompletableFuture(): CompletableFuture = CompletableFutureUtils.anyOfSuccess(*this) -//////////////////////////////////////// -//# allTupleOf/allTupleOfFastFail methods -//////////////////////////////////////// - -/** - * Returns a new CompletableFuture that is completed when the given two CompletableFutures complete. - * If any of the given CompletableFutures complete exceptionally, then the returned - * CompletableFuture also does so, with a CompletionException holding this exception as its cause. - * - * @return a new CompletableFuture that is completed when the given 2 CompletableFutures complete - * @throws NullPointerException if any input CompletableFutures are `null` - * @see CompletableFutureUtils.allTupleOf - * @see allResultsOfCompletableFuture - * @see CompletableFuture.allOf - */ -fun CompletableFuture.allTupleOf(cf2: CompletableFuture): CompletableFuture> = - CompletableFutureUtils.allTupleOf(this, cf2) - -/** - * Returns a new CompletableFuture that is successful when the given two CompletableFutures success. - * If any of the given CompletableFutures complete exceptionally, then the returned - * CompletableFuture also does so *without* waiting other incomplete given CompletableFutures, - * with a CompletionException holding this exception as its cause. - * - * @return a new CompletableFuture that is successful when the given two CompletableFutures success - * @throws NullPointerException if any of the given CompletableFutures are {@code null} - * @see CompletableFutureUtils.allTupleOfFastFail - * @see allResultsOfFastFailCompletableFuture - * @see CompletableFutureUtils.allOfFastFail - */ -fun CompletableFuture.allTupleOfFastFail(cf2: CompletableFuture): CompletableFuture> = - CompletableFutureUtils.allTupleOfFastFail(this, cf2) - -/** - * Returns a new CompletableFuture that is completed when the given three CompletableFutures complete. - * If any of the given CompletableFutures complete exceptionally, then the returned - * CompletableFuture also does so, with a CompletionException holding this exception as its cause. - * - * @return a new CompletableFuture that is completed when the given 3 CompletableFutures complete - * @throws NullPointerException if any input CompletableFutures are `null` - * @see CompletableFutureUtils.allTupleOf - * @see allResultsOfCompletableFuture - * @see CompletableFuture.allOf - */ -fun CompletableFuture.allTupleOf( - cf2: CompletableFuture, cf3: CompletableFuture -): CompletableFuture> = - CompletableFutureUtils.allTupleOf(this, cf2, cf3) - -/** - * Returns a new CompletableFuture that is successful when the given three CompletableFutures success. - * If any of the given CompletableFutures complete exceptionally, then the returned - * CompletableFuture also does so *without* waiting other incomplete given CompletableFutures, - * with a CompletionException holding this exception as its cause. - * - * @return a new CompletableFuture that is successful when the given three CompletableFutures success - * @throws NullPointerException if any of the given CompletableFutures are {@code null} - * @see CompletableFutureUtils.allTupleOfFastFail - * @see allResultsOfFastFailCompletableFuture - * @see CompletableFutureUtils.allOfFastFail - */ -fun CompletableFuture.allTupleOfFastFail( - cf2: CompletableFuture, cf3: CompletableFuture -): CompletableFuture> = - CompletableFutureUtils.allTupleOfFastFail(this, cf2, cf3) - -/** - * Returns a new CompletableFuture that is completed when the given 4 CompletableFutures complete. - * If any of the given CompletableFutures complete exceptionally, then the returned - * CompletableFuture also does so, with a CompletionException holding this exception as its cause. - * - * @return a new CompletableFuture that is completed when the given 4 CompletableFutures complete - * @throws NullPointerException if any input CompletableFutures are `null` - * @see CompletableFutureUtils.allTupleOf - * @see allResultsOfCompletableFuture - * @see CompletableFuture.allOf - */ -fun CompletableFuture.allTupleOf( - cf2: CompletableFuture, cf3: CompletableFuture, cf4: CompletableFuture -): CompletableFuture> = - CompletableFutureUtils.allTupleOf(this, cf2, cf3, cf4) - -/** - * Returns a new CompletableFuture that is successful when the given 4 CompletableFutures success. - * If any of the given CompletableFutures complete exceptionally, then the returned - * CompletableFuture also does so *without* waiting other incomplete given CompletableFutures, - * with a CompletionException holding this exception as its cause. - * - * @return a new CompletableFuture that is successful when the given 4 CompletableFutures success - * @throws NullPointerException if any of the given CompletableFutures are {@code null} - * @see CompletableFutureUtils.allTupleOfFastFail - * @see allResultsOfFastFailCompletableFuture - * @see CompletableFutureUtils.allOfFastFail - */ -fun CompletableFuture.allTupleOfFastFail( - cf2: CompletableFuture, cf3: CompletableFuture, cf4: CompletableFuture -): CompletableFuture> = - CompletableFutureUtils.allTupleOfFastFail(this, cf2, cf3, cf4) - -/** - * Returns a new CompletableFuture that is completed when the given 5 CompletableFutures complete. - * If any of the given CompletableFutures complete exceptionally, then the returned - * CompletableFuture also does so, with a CompletionException holding this exception as its cause. - * - * @return a new CompletableFuture that is completed when the given 5 CompletableFutures complete - * @throws NullPointerException if any input CompletableFutures are `null` - * @see CompletableFutureUtils.allTupleOf - * @see allResultsOfCompletableFuture - * @see CompletableFuture.allOf - */ -fun CompletableFuture.allTupleOf( - cf2: CompletableFuture, cf3: CompletableFuture, - cf4: CompletableFuture, cf5: CompletableFuture -): CompletableFuture> = - CompletableFutureUtils.allTupleOf(this, cf2, cf3, cf4, cf5) - -/** - * Returns a new CompletableFuture that is successful when the given 5 CompletableFutures success. - * If any of the given CompletableFutures complete exceptionally, then the returned - * CompletableFuture also does so *without* waiting other incomplete given CompletableFutures, - * with a CompletionException holding this exception as its cause. - * - * @return a new CompletableFuture that is successful when the given 5 CompletableFutures success - * @throws NullPointerException if any of the given CompletableFutures are {@code null} - * @see CompletableFutureUtils.allTupleOfFastFail - * @see allResultsOfFastFailCompletableFuture - * @see CompletableFutureUtils.allOfFastFail - */ -fun CompletableFuture.allTupleOfFastFail( - cf2: CompletableFuture, cf3: CompletableFuture, - cf4: CompletableFuture, cf5: CompletableFuture -): CompletableFuture> = - CompletableFutureUtils.allTupleOfFastFail(this, cf2, cf3, cf4, cf5) - //////////////////////////////////////////////////////////////////////////////// //# `then both(binary input)` methods with fast-fail support: // @@ -564,6 +428,143 @@ fun CompletionStage.thenCombineFastFailAsync( ): CompletableFuture = CompletableFutureUtils.thenCombineFastFailAsync(this, cf2, fn, executor) +//////////////////////////////////////// +//# allTupleOf* methods +// +// - allTupleOf +// - allTupleOfFastFail +//////////////////////////////////////// + +/** + * Returns a new CompletableFuture that is completed when the given two CompletableFutures complete. + * If any of the given CompletableFutures complete exceptionally, then the returned + * CompletableFuture also does so, with a CompletionException holding this exception as its cause. + * + * @return a new CompletableFuture that is completed when the given 2 CompletableFutures complete + * @throws NullPointerException if any input CompletableFutures are `null` + * @see CompletableFutureUtils.allTupleOf + * @see allResultsOfCompletableFuture + * @see CompletableFuture.allOf + */ +fun CompletableFuture.allTupleOf(cf2: CompletableFuture): CompletableFuture> = + CompletableFutureUtils.allTupleOf(this, cf2) + +/** + * Returns a new CompletableFuture that is successful when the given two CompletableFutures success. + * If any of the given CompletableFutures complete exceptionally, then the returned + * CompletableFuture also does so *without* waiting other incomplete given CompletableFutures, + * with a CompletionException holding this exception as its cause. + * + * @return a new CompletableFuture that is successful when the given two CompletableFutures success + * @throws NullPointerException if any of the given CompletableFutures are {@code null} + * @see CompletableFutureUtils.allTupleOfFastFail + * @see allResultsOfFastFailCompletableFuture + * @see CompletableFutureUtils.allOfFastFail + */ +fun CompletableFuture.allTupleOfFastFail(cf2: CompletableFuture): CompletableFuture> = + CompletableFutureUtils.allTupleOfFastFail(this, cf2) + +/** + * Returns a new CompletableFuture that is completed when the given three CompletableFutures complete. + * If any of the given CompletableFutures complete exceptionally, then the returned + * CompletableFuture also does so, with a CompletionException holding this exception as its cause. + * + * @return a new CompletableFuture that is completed when the given 3 CompletableFutures complete + * @throws NullPointerException if any input CompletableFutures are `null` + * @see CompletableFutureUtils.allTupleOf + * @see allResultsOfCompletableFuture + * @see CompletableFuture.allOf + */ +fun CompletableFuture.allTupleOf( + cf2: CompletableFuture, cf3: CompletableFuture +): CompletableFuture> = + CompletableFutureUtils.allTupleOf(this, cf2, cf3) + +/** + * Returns a new CompletableFuture that is successful when the given three CompletableFutures success. + * If any of the given CompletableFutures complete exceptionally, then the returned + * CompletableFuture also does so *without* waiting other incomplete given CompletableFutures, + * with a CompletionException holding this exception as its cause. + * + * @return a new CompletableFuture that is successful when the given three CompletableFutures success + * @throws NullPointerException if any of the given CompletableFutures are {@code null} + * @see CompletableFutureUtils.allTupleOfFastFail + * @see allResultsOfFastFailCompletableFuture + * @see CompletableFutureUtils.allOfFastFail + */ +fun CompletableFuture.allTupleOfFastFail( + cf2: CompletableFuture, cf3: CompletableFuture +): CompletableFuture> = + CompletableFutureUtils.allTupleOfFastFail(this, cf2, cf3) + +/** + * Returns a new CompletableFuture that is completed when the given 4 CompletableFutures complete. + * If any of the given CompletableFutures complete exceptionally, then the returned + * CompletableFuture also does so, with a CompletionException holding this exception as its cause. + * + * @return a new CompletableFuture that is completed when the given 4 CompletableFutures complete + * @throws NullPointerException if any input CompletableFutures are `null` + * @see CompletableFutureUtils.allTupleOf + * @see allResultsOfCompletableFuture + * @see CompletableFuture.allOf + */ +fun CompletableFuture.allTupleOf( + cf2: CompletableFuture, cf3: CompletableFuture, cf4: CompletableFuture +): CompletableFuture> = + CompletableFutureUtils.allTupleOf(this, cf2, cf3, cf4) + +/** + * Returns a new CompletableFuture that is successful when the given 4 CompletableFutures success. + * If any of the given CompletableFutures complete exceptionally, then the returned + * CompletableFuture also does so *without* waiting other incomplete given CompletableFutures, + * with a CompletionException holding this exception as its cause. + * + * @return a new CompletableFuture that is successful when the given 4 CompletableFutures success + * @throws NullPointerException if any of the given CompletableFutures are {@code null} + * @see CompletableFutureUtils.allTupleOfFastFail + * @see allResultsOfFastFailCompletableFuture + * @see CompletableFutureUtils.allOfFastFail + */ +fun CompletableFuture.allTupleOfFastFail( + cf2: CompletableFuture, cf3: CompletableFuture, cf4: CompletableFuture +): CompletableFuture> = + CompletableFutureUtils.allTupleOfFastFail(this, cf2, cf3, cf4) + +/** + * Returns a new CompletableFuture that is completed when the given 5 CompletableFutures complete. + * If any of the given CompletableFutures complete exceptionally, then the returned + * CompletableFuture also does so, with a CompletionException holding this exception as its cause. + * + * @return a new CompletableFuture that is completed when the given 5 CompletableFutures complete + * @throws NullPointerException if any input CompletableFutures are `null` + * @see CompletableFutureUtils.allTupleOf + * @see allResultsOfCompletableFuture + * @see CompletableFuture.allOf + */ +fun CompletableFuture.allTupleOf( + cf2: CompletableFuture, cf3: CompletableFuture, + cf4: CompletableFuture, cf5: CompletableFuture +): CompletableFuture> = + CompletableFutureUtils.allTupleOf(this, cf2, cf3, cf4, cf5) + +/** + * Returns a new CompletableFuture that is successful when the given 5 CompletableFutures success. + * If any of the given CompletableFutures complete exceptionally, then the returned + * CompletableFuture also does so *without* waiting other incomplete given CompletableFutures, + * with a CompletionException holding this exception as its cause. + * + * @return a new CompletableFuture that is successful when the given 5 CompletableFutures success + * @throws NullPointerException if any of the given CompletableFutures are {@code null} + * @see CompletableFutureUtils.allTupleOfFastFail + * @see allResultsOfFastFailCompletableFuture + * @see CompletableFutureUtils.allOfFastFail + */ +fun CompletableFuture.allTupleOfFastFail( + cf2: CompletableFuture, cf3: CompletableFuture, + cf4: CompletableFuture, cf5: CompletableFuture +): CompletableFuture> = + CompletableFutureUtils.allTupleOfFastFail(this, cf2, cf3, cf4, cf5) + //////////////////////////////////////////////////////////////////////////////// //# `then either(binary input)` methods with either(any)-success support: // @@ -728,7 +729,7 @@ fun CompletionStage.applyToEitherSuccessAsync( CompletableFutureUtils.applyToEitherSuccessAsync(this, cf2, fn, executor) //////////////////////////////////////////////////////////////////////////////// -//# More new enhanced methods +//# New enhanced methods //////////////////////////////////////////////////////////////////////////////// /** diff --git a/cffu-kotlin/src/test/java/io/foldright/cffu/test/CompletableFutureExtensionsTest.kt b/cffu-kotlin/src/test/java/io/foldright/cffu/test/CompletableFutureExtensionsTest.kt index 8da1db2a..762b8709 100644 --- a/cffu-kotlin/src/test/java/io/foldright/cffu/test/CompletableFutureExtensionsTest.kt +++ b/cffu-kotlin/src/test/java/io/foldright/cffu/test/CompletableFutureExtensionsTest.kt @@ -332,7 +332,7 @@ class CompletableFutureExtensionsTest : FunSpec({ } //////////////////////////////////////////////////////////////////////////////// - //# More new enhanced methods + //# New enhanced methods //////////////////////////////////////////////////////////////////////////////// test("peek") {