From 9ea393d4b9365e86afd15d394549602a95c2c7c8 Mon Sep 17 00:00:00 2001 From: huhaosumail Date: Tue, 25 Jun 2024 17:56:16 +0800 Subject: [PATCH 1/3] =?UTF-8?q?`CompletableFutureUtils`=E8=A1=A5=E5=85=85?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E7=9A=84`tupleMSupplyMostSuccessAsync`?= =?UTF-8?q?=E4=B8=8E`thenTupleMApplyMostSuccessAsync`=E6=96=B9=E6=B3=95?= =?UTF-8?q?=EF=BC=8C=E4=BC=98=E5=8C=96=E7=9B=B8=E5=85=B3=E5=8D=95=E5=85=83?= =?UTF-8?q?=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cffu/CompletableFutureUtils.java | 338 ++++++++++++++++-- .../cffu/CompletableFutureUtilsTest.java | 43 +++ 2 files changed, 358 insertions(+), 23 deletions(-) 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 622ef804a..05c1c475f 100644 --- a/cffu-core/src/main/java/io/foldright/cffu/CompletableFutureUtils.java +++ b/cffu-core/src/main/java/io/foldright/cffu/CompletableFutureUtils.java @@ -429,12 +429,36 @@ public static CompletableFuture> /** * Returns a new CompletableFuture that is asynchronously completed - * by tasks running in the given Executor with the values obtained by calling the given Suppliers + * by tasks running in the CompletableFuture's default asynchronous execution facility + * with the most values obtained by calling the given Suppliers + * in the given time({@code timeout}, aka as many results as possible in the given time) * in the same order of the given Suppliers arguments. *

- * This method is the same as {@link #tupleMSupplyAsync(Executor, Supplier, Supplier)} except for the most-success behavior. + * If the given supplier is successful in the given time, the return result is the completed value; + * Otherwise the given valueIfNotSuccess. * - * @param executor the executor to use for asynchronous execution + * @param timeout how long to wait in units of {@code unit} + * @param unit a {@code TimeUnit} determining how to interpret the {@code timeout} parameter + * @return the new CompletableFuture + */ + public static CompletableFuture> tupleMSupplyMostSuccessAsync( + long timeout, TimeUnit unit, + Supplier supplier1, Supplier supplier2) { + return tupleMSupplyMostSuccessAsync(AsyncPoolHolder.ASYNC_POOL, timeout, unit, supplier1, supplier2); + } + + /** + * Returns a new CompletableFuture that is asynchronously completed + * by tasks running in the CompletableFuture's default asynchronous execution facility + * with the most values obtained by calling the given Suppliers + * in the given time({@code timeout}, aka as many results as possible in the given time) + * in the same order of the given Suppliers arguments. + *

+ * If the given supplier is successful in the given time, the return result is the completed value; + * Otherwise the given valueIfNotSuccess. + * + * @param timeout how long to wait in units of {@code unit} + * @param unit a {@code TimeUnit} determining how to interpret the {@code timeout} parameter * @return the new CompletableFuture */ public static CompletableFuture> tupleMSupplyMostSuccessAsync( @@ -449,13 +473,36 @@ public static CompletableFuture> tupleMSupplyMostSuccess /** * Returns a new CompletableFuture that is asynchronously completed - * by tasks running in the given Executor with the values obtained by calling the given Suppliers + * by tasks running in the CompletableFuture's default asynchronous execution facility + * with the most values obtained by calling the given Suppliers + * in the given time({@code timeout}, aka as many results as possible in the given time) * in the same order of the given Suppliers arguments. *

- * This method is the same as {@link #tupleMSupplyAsync(Executor, Supplier, Supplier, Supplier)} - * except for the most-success behavior. + * If the given supplier is successful in the given time, the return result is the completed value; + * Otherwise the given valueIfNotSuccess. * - * @param executor the executor to use for asynchronous execution + * @param timeout how long to wait in units of {@code unit} + * @param unit a {@code TimeUnit} determining how to interpret the {@code timeout} parameter + * @return the new CompletableFuture + */ + public static CompletableFuture> tupleMSupplyMostSuccessAsync( + long timeout, TimeUnit unit, + Supplier supplier1, Supplier supplier2, Supplier supplier3) { + return tupleMSupplyMostSuccessAsync(AsyncPoolHolder.ASYNC_POOL, timeout, unit, supplier1, supplier2, supplier3); + } + + /** + * Returns a new CompletableFuture that is asynchronously completed + * by tasks running in the CompletableFuture's default asynchronous execution facility + * with the most values obtained by calling the given Suppliers + * in the given time({@code timeout}, aka as many results as possible in the given time) + * in the same order of the given Suppliers arguments. + *

+ * If the given supplier is successful in the given time, the return result is the completed value; + * Otherwise the given valueIfNotSuccess. + * + * @param timeout how long to wait in units of {@code unit} + * @param unit a {@code TimeUnit} determining how to interpret the {@code timeout} parameter * @return the new CompletableFuture */ public static CompletableFuture> tupleMSupplyMostSuccessAsync( @@ -470,13 +517,36 @@ public static CompletableFuture> tupleMSupplyMos /** * Returns a new CompletableFuture that is asynchronously completed - * by tasks running in the given Executor with the values obtained by calling the given Suppliers + * by tasks running in the CompletableFuture's default asynchronous execution facility + * with the most values obtained by calling the given Suppliers + * in the given time({@code timeout}, aka as many results as possible in the given time) * in the same order of the given Suppliers arguments. *

- * This method is the same as {@link #tupleMSupplyAsync(Executor, Supplier, Supplier, Supplier, Supplier)} - * except for the most-success behavior. + * If the given supplier is successful in the given time, the return result is the completed value; + * Otherwise the given valueIfNotSuccess. * - * @param executor the executor to use for asynchronous execution + * @param timeout how long to wait in units of {@code unit} + * @param unit a {@code TimeUnit} determining how to interpret the {@code timeout} parameter + * @return the new CompletableFuture + */ + public static CompletableFuture> tupleMSupplyMostSuccessAsync( + long timeout, TimeUnit unit, Supplier supplier1, + Supplier supplier2, Supplier supplier3, Supplier supplier4) { + return tupleMSupplyMostSuccessAsync(AsyncPoolHolder.ASYNC_POOL, timeout, unit, supplier1, supplier2, supplier3, supplier4); + } + + /** + * Returns a new CompletableFuture that is asynchronously completed + * by tasks running in the CompletableFuture's default asynchronous execution facility + * with the most values obtained by calling the given Suppliers + * in the given time({@code timeout}, aka as many results as possible in the given time) + * in the same order of the given Suppliers arguments. + *

+ * If the given supplier is successful in the given time, the return result is the completed value; + * Otherwise the given valueIfNotSuccess. + * + * @param timeout how long to wait in units of {@code unit} + * @param unit a {@code TimeUnit} determining how to interpret the {@code timeout} parameter * @return the new CompletableFuture */ public static CompletableFuture> tupleMSupplyMostSuccessAsync( @@ -491,13 +561,37 @@ public static CompletableFuture> tupleMS /** * Returns a new CompletableFuture that is asynchronously completed - * by tasks running in the given Executor with the values obtained by calling the given Suppliers + * by tasks running in the CompletableFuture's default asynchronous execution facility + * with the most values obtained by calling the given Suppliers + * in the given time({@code timeout}, aka as many results as possible in the given time) * in the same order of the given Suppliers arguments. *

- * This method is the same as {@link #tupleMSupplyAsync(Executor, Supplier, Supplier, Supplier, Supplier, Supplier)} - * except for the most-success behavior. + * If the given supplier is successful in the given time, the return result is the completed value; + * Otherwise the given valueIfNotSuccess. * - * @param executor the executor to use for asynchronous execution + * @param timeout how long to wait in units of {@code unit} + * @param unit a {@code TimeUnit} determining how to interpret the {@code timeout} parameter + * @return the new CompletableFuture + */ + public static CompletableFuture> tupleMSupplyMostSuccessAsync( + long timeout, TimeUnit unit, Supplier supplier1, + Supplier supplier2, Supplier supplier3, + Supplier supplier4, Supplier supplier5) { + return tupleMSupplyMostSuccessAsync(AsyncPoolHolder.ASYNC_POOL, timeout, unit, supplier1, supplier2, supplier3, supplier4, supplier5); + } + + /** + * Returns a new CompletableFuture that is asynchronously completed + * by tasks running in the CompletableFuture's default asynchronous execution facility + * with the most values obtained by calling the given Suppliers + * in the given time({@code timeout}, aka as many results as possible in the given time) + * in the same order of the given Suppliers arguments. + *

+ * If the given supplier is successful in the given time, the return result is the completed value; + * Otherwise the given valueIfNotSuccess. + * + * @param timeout how long to wait in units of {@code unit} + * @param unit a {@code TimeUnit} determining how to interpret the {@code timeout} parameter * @return the new CompletableFuture */ public static CompletableFuture> tupleMSupplyMostSuccessAsync( @@ -1555,8 +1649,9 @@ public static CompletableFuture> thenMApplyFastFailAsync( * This method is the same as {@link #thenMApplyAsync(CompletionStage, Executor, Function[])} * except for the fast-fail behavior. * - * @param fns the functions to use to compute the values of the returned CompletableFuture - * @param the functions' return type + * @param fns the functions to use to compute the values of the returned CompletableFuture + * @param executor the executor to use for asynchronous execution + * @param the functions' return type * @return the new CompletableFuture */ @SafeVarargs @@ -1648,8 +1743,9 @@ public static CompletableFuture> thenMApplyAsync( * (with the given stage's result as the argument to the given functions) * in the same order of the given Functions arguments. * - * @param fns the functions to use to compute the values of the returned CompletableFuture - * @param the functions' return type + * @param executor the executor to use for asynchronous execution + * @param fns the functions to use to compute the values of the returned CompletableFuture + * @param the functions' return type * @return the new CompletableFuture */ @SafeVarargs @@ -1691,7 +1787,8 @@ public static CompletableFuture thenMAcceptAsync( * Returns a new CompletableFuture that, when the given stage completes normally, * is executed using the given Executor, with the given stage's result as the argument to the given actions. * - * @param actions the actions to perform before completing the returned CompletableFuture + * @param executor the executor to use for asynchronous execution + * @param actions the actions to perform before completing the returned CompletableFuture * @return the new CompletableFuture */ @SafeVarargs @@ -1728,7 +1825,8 @@ public static CompletableFuture thenMAcceptFastFailAsync( * This method is the same as {@link #thenMAcceptAsync(CompletionStage, Executor, Consumer[])} * except for the fast-fail behavior. * - * @param actions the actions to perform before completing the returned CompletableFuture + * @param executor the executor to use for asynchronous execution + * @param actions the actions to perform before completing the returned CompletableFuture * @return the new CompletableFuture */ @SafeVarargs @@ -1774,7 +1872,8 @@ public static CompletableFuture thenMRunFastFailAsync(CompletionStage c * This method is the same as {@link #thenMRunAsync(CompletionStage, Executor, Runnable...)} * except for the fast-fail behavior. * - * @param actions the actions to perform before completing the returned CompletableFuture + * @param executor the executor to use for asynchronous execution + * @param actions the actions to perform before completing the returned CompletableFuture * @return the new CompletableFuture * @see CompletableFuture#thenRunAsync(Runnable, Executor) * @see #allOfFastFail(CompletionStage[]) @@ -1805,7 +1904,8 @@ public static CompletableFuture thenMRunAsync(CompletionStage cf, Runna * Returns a new CompletableFuture that, when the given stage completes normally, * executes the given actions using the given Executor. * - * @param actions the actions to perform before completing the returned CompletableFuture + * @param executor the executor to use for asynchronous execution + * @param actions the actions to perform before completing the returned CompletableFuture * @return the new CompletableFuture * @see CompletableFuture#thenRunAsync(Runnable, Executor) * @see #allOf(CompletionStage[]) @@ -1983,6 +2083,198 @@ public static CompletableFuture allTupleOf0(true, wrapFunctions(executor, v, fns))); } + /** + * Returns a new CompletableFuture that, when the given stage completes normally, + * is executed using the CompletableFuture's default asynchronous execution facility, + * with the most values obtained by calling the given Functions + * (with the given stage's result as the argument to the given functions) + * in the given time({@code timeout}, aka as many results as possible in the given time) + * in the same order of the given Functions arguments. + *

+ * If the given function is successful in the given time, the return result is the completed value; + * Otherwise the given valueIfNotSuccess. + * + * @param timeout how long to wait in units of {@code unit} + * @param unit a {@code TimeUnit} determining how to interpret the {@code timeout} parameter + * @return the new CompletableFuture + */ + public static CompletableFuture> thenTupleMApplyMostSuccessAsync( + CompletionStage cf, + long timeout, TimeUnit unit, Function fn1, Function fn2) { + return thenTupleMApplyMostSuccessAsync(cf, AsyncPoolHolder.ASYNC_POOL, timeout, unit, fn1, fn2); + } + + /** + * Returns a new CompletableFuture that, when the given stage completes normally, + * is executed using the CompletableFuture's default asynchronous execution facility, + * with the most values obtained by calling the given Functions + * (with the given stage's result as the argument to the given functions) + * in the given time({@code timeout}, aka as many results as possible in the given time) + * in the same order of the given Functions arguments. + *

+ * If the given function is successful in the given time, the return result is the completed value; + * Otherwise the given valueIfNotSuccess. + * + * @param executor the executor to use for asynchronous execution + * @param timeout how long to wait in units of {@code unit} + * @param unit a {@code TimeUnit} determining how to interpret the {@code timeout} parameter + * @return the new CompletableFuture + */ + public static CompletableFuture> thenTupleMApplyMostSuccessAsync( + CompletionStage cf, Executor executor, long timeout, TimeUnit unit, Function fn1, Function fn2) { + requireNonNull(executor, "executor is null"); + requireNonNull(unit, "unit is null"); + requireArrayAndEleNonNull("fn", fn1, fn2); + + return f_toCf(cf).thenCompose(v -> mostTupleOfSuccess0(executor, timeout, unit, CompletableFuture.supplyAsync(() -> fn1.apply(v), executor), CompletableFuture.supplyAsync(() -> fn2.apply(v), executor))); + } + + /** + * Returns a new CompletableFuture that, when the given stage completes normally, + * is executed using the CompletableFuture's default asynchronous execution facility, + * with the most values obtained by calling the given Functions + * (with the given stage's result as the argument to the given functions) + * in the given time({@code timeout}, aka as many results as possible in the given time) + * in the same order of the given Functions arguments. + *

+ * If the given function is successful in the given time, the return result is the completed value; + * Otherwise the given valueIfNotSuccess. + * + * @param timeout how long to wait in units of {@code unit} + * @param unit a {@code TimeUnit} determining how to interpret the {@code timeout} parameter + * @return the new CompletableFuture + */ + public static CompletableFuture> thenTupleMApplyMostSuccessAsync( + CompletionStage cf, + long timeout, TimeUnit unit, Function fn1, Function fn2, Function fn3) { + return thenTupleMApplyMostSuccessAsync(cf, AsyncPoolHolder.ASYNC_POOL, timeout, unit, fn1, fn2, fn3); + } + + /** + * Returns a new CompletableFuture that, when the given stage completes normally, + * is executed using the CompletableFuture's default asynchronous execution facility, + * with the most values obtained by calling the given Functions + * (with the given stage's result as the argument to the given functions) + * in the given time({@code timeout}, aka as many results as possible in the given time) + * in the same order of the given Functions arguments. + *

+ * If the given function is successful in the given time, the return result is the completed value; + * Otherwise the given valueIfNotSuccess. + * + * @param executor the executor to use for asynchronous execution + * @param timeout how long to wait in units of {@code unit} + * @param unit a {@code TimeUnit} determining how to interpret the {@code timeout} parameter + * @return the new CompletableFuture + */ + public static CompletableFuture> thenTupleMApplyMostSuccessAsync( + CompletionStage cf, Executor executor, long timeout, TimeUnit unit, Function fn1, Function fn2, Function fn3) { + requireNonNull(executor, "executor is null"); + requireNonNull(unit, "unit is null"); + requireArrayAndEleNonNull("fn", fn1, fn2, fn3); + + return f_toCf(cf).thenCompose(v -> mostTupleOfSuccess0(executor, timeout, unit, CompletableFuture.supplyAsync(() -> fn1.apply(v), executor), + CompletableFuture.supplyAsync(() -> fn2.apply(v), executor), CompletableFuture.supplyAsync(() -> fn3.apply(v), executor))); + } + + /** + * Returns a new CompletableFuture that, when the given stage completes normally, + * is executed using the CompletableFuture's default asynchronous execution facility, + * with the most values obtained by calling the given Functions + * (with the given stage's result as the argument to the given functions) + * in the given time({@code timeout}, aka as many results as possible in the given time) + * in the same order of the given Functions arguments. + *

+ * If the given function is successful in the given time, the return result is the completed value; + * Otherwise the given valueIfNotSuccess. + * + * @param timeout how long to wait in units of {@code unit} + * @param unit a {@code TimeUnit} determining how to interpret the {@code timeout} parameter + * @return the new CompletableFuture + */ + public static CompletableFuture> thenTupleMApplyMostSuccessAsync( + CompletionStage cf, long timeout, TimeUnit unit, Function fn1, + Function fn2, Function fn3, Function fn4) { + return thenTupleMApplyMostSuccessAsync(cf, AsyncPoolHolder.ASYNC_POOL, timeout, unit, fn1, fn2, fn3, fn4); + } + + /** + * Returns a new CompletableFuture that, when the given stage completes normally, + * is executed using the CompletableFuture's default asynchronous execution facility, + * with the most values obtained by calling the given Functions + * (with the given stage's result as the argument to the given functions) + * in the given time({@code timeout}, aka as many results as possible in the given time) + * in the same order of the given Functions arguments. + *

+ * If the given function is successful in the given time, the return result is the completed value; + * Otherwise the given valueIfNotSuccess. + * + * @param executor the executor to use for asynchronous execution + * @param timeout how long to wait in units of {@code unit} + * @param unit a {@code TimeUnit} determining how to interpret the {@code timeout} parameter + * @return the new CompletableFuture + */ + public static CompletableFuture> thenTupleMApplyMostSuccessAsync( + CompletionStage cf, Executor executor, long timeout, TimeUnit unit, Function fn1, + Function fn2, Function fn3, Function fn4) { + requireNonNull(executor, "executor is null"); + requireNonNull(unit, "unit is null"); + requireArrayAndEleNonNull("fn", fn1, fn2, fn3, fn4); + + return f_toCf(cf).thenCompose(v -> mostTupleOfSuccess0(executor, timeout, unit, CompletableFuture.supplyAsync(() -> fn1.apply(v), executor), + CompletableFuture.supplyAsync(() -> fn2.apply(v), executor), CompletableFuture.supplyAsync(() -> fn3.apply(v), executor), CompletableFuture.supplyAsync(() -> fn4.apply(v), executor))); + } + + /** + * Returns a new CompletableFuture that, when the given stage completes normally, + * is executed using the CompletableFuture's default asynchronous execution facility, + * with the most values obtained by calling the given Functions + * (with the given stage's result as the argument to the given functions) + * in the given time({@code timeout}, aka as many results as possible in the given time) + * in the same order of the given Functions arguments. + *

+ * If the given function is successful in the given time, the return result is the completed value; + * Otherwise the given valueIfNotSuccess. + * + * @param timeout how long to wait in units of {@code unit} + * @param unit a {@code TimeUnit} determining how to interpret the {@code timeout} parameter + * @return the new CompletableFuture + */ + public static CompletableFuture> thenTupleMApplyMostSuccessAsync( + CompletionStage cf, long timeout, TimeUnit unit, Function fn1, + Function fn2, Function fn3, Function fn4, + Function fn5) { + return thenTupleMApplyMostSuccessAsync(cf, AsyncPoolHolder.ASYNC_POOL, timeout, unit, fn1, fn2, fn3, fn4, fn5); + } + + /** + * Returns a new CompletableFuture that, when the given stage completes normally, + * is executed using the CompletableFuture's default asynchronous execution facility, + * with the most values obtained by calling the given Functions + * (with the given stage's result as the argument to the given functions) + * in the given time({@code timeout}, aka as many results as possible in the given time) + * in the same order of the given Functions arguments. + *

+ * If the given function is successful in the given time, the return result is the completed value; + * Otherwise the given valueIfNotSuccess. + * + * @param executor the executor to use for asynchronous execution + * @param timeout how long to wait in units of {@code unit} + * @param unit a {@code TimeUnit} determining how to interpret the {@code timeout} parameter + * @return the new CompletableFuture + */ + public static CompletableFuture> thenTupleMApplyMostSuccessAsync( + CompletionStage cf, Executor executor, long timeout, TimeUnit unit, Function fn1, + Function fn2, Function fn3, Function fn4, + Function fn5) { + requireNonNull(executor, "executor is null"); + requireNonNull(unit, "unit is null"); + requireArrayAndEleNonNull("fn", fn1, fn2, fn3, fn4, fn5); + + return f_toCf(cf).thenCompose(v -> mostTupleOfSuccess0(executor, timeout, unit, CompletableFuture.supplyAsync(() -> fn1.apply(v), executor), + CompletableFuture.supplyAsync(() -> fn2.apply(v), executor), CompletableFuture.supplyAsync(() -> fn3.apply(v), executor), + CompletableFuture.supplyAsync(() -> fn4.apply(v), executor), CompletableFuture.supplyAsync(() -> fn5.apply(v), executor))); + } + /** * Returns a new CompletableFuture that, when the given stage completes normally, * is executed using the CompletableFuture's default asynchronous execution facility, 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 9ecf9a453..70cd81121 100644 --- a/cffu-core/src/test/java/io/foldright/cffu/CompletableFutureUtilsTest.java +++ b/cffu-core/src/test/java/io/foldright/cffu/CompletableFutureUtilsTest.java @@ -809,15 +809,58 @@ void test_tupleMSupplyMostSuccessAsync() throws Exception { sleep(10); return n + n; }; + assertEquals(Tuple2.of(n, s), tupleMSupplyMostSuccessAsync(100, TimeUnit.MILLISECONDS, supplier_n, supplier_s).get()); assertEquals(Tuple2.of(n, s), tupleMSupplyMostSuccessAsync(defaultExecutor(), 100, TimeUnit.MILLISECONDS, supplier_n, supplier_s).get()); + assertEquals(Tuple3.of(n, s, d), tupleMSupplyMostSuccessAsync(100, TimeUnit.MILLISECONDS, supplier_n, supplier_s, supplier_d).get()); assertEquals(Tuple3.of(n, s, d), tupleMSupplyMostSuccessAsync(defaultExecutor(), 100, TimeUnit.MILLISECONDS, supplier_n, supplier_s, supplier_d).get()); + assertEquals(Tuple4.of(n, s, d, anotherN), tupleMSupplyMostSuccessAsync(100, TimeUnit.MILLISECONDS, supplier_n, supplier_s, supplier_d, supplier_an).get()); assertEquals(Tuple4.of(n, s, d, anotherN), tupleMSupplyMostSuccessAsync(defaultExecutor(), 100, TimeUnit.MILLISECONDS, supplier_n, supplier_s, supplier_d, supplier_an).get()); + assertEquals(Tuple5.of(n, s, d, anotherN, n + n), tupleMSupplyMostSuccessAsync(100, TimeUnit.MILLISECONDS, supplier_n, supplier_s, supplier_d, supplier_an, supplier_nn).get()); assertEquals(Tuple5.of(n, s, d, anotherN, n + n), tupleMSupplyMostSuccessAsync(defaultExecutor(), 100, TimeUnit.MILLISECONDS, supplier_n, supplier_s, supplier_d, supplier_an, supplier_nn).get()); } + + @Test + void test_tupleMApplyMostSuccessAsync() throws Exception { + final CompletableFuture completed = completedFuture(n); + final Function function_n = (x) -> { + sleep(100); + return n; + }; + + final Function function_s = (x) -> { + sleep(100); + return s; + }; + + final Function function_d = (x) -> { + sleep(100); + return d; + }; + final Function function_an = (x) -> { + sleep(100); + return anotherN; + }; + final Function function_nn = (x) -> { + sleep(100); + return n + n; + }; + assertEquals(Tuple2.of(n, s), thenTupleMApplyMostSuccessAsync(completed, 500, TimeUnit.MILLISECONDS, function_n, function_s).get()); + assertEquals(Tuple2.of(n, s), thenTupleMApplyMostSuccessAsync(completed, defaultExecutor(), 500, TimeUnit.MILLISECONDS, function_n, function_s).get()); + + assertEquals(Tuple3.of(n, s, d), thenTupleMApplyMostSuccessAsync(completed, 500, TimeUnit.MILLISECONDS, function_n, function_s, function_d).get()); + assertEquals(Tuple3.of(n, s, d), thenTupleMApplyMostSuccessAsync(completed, defaultExecutor(), 500, TimeUnit.MILLISECONDS, function_n, function_s, function_d).get()); + + assertEquals(Tuple4.of(n, s, d, anotherN), thenTupleMApplyMostSuccessAsync(completed, 500, TimeUnit.MILLISECONDS, function_n, function_s, function_d, function_an).get()); + assertEquals(Tuple4.of(n, s, d, anotherN), thenTupleMApplyMostSuccessAsync(completed, defaultExecutor(), 500, TimeUnit.MILLISECONDS, function_n, function_s, function_d, function_an).get()); + + assertEquals(Tuple5.of(n, s, d, anotherN, n + n), thenTupleMApplyMostSuccessAsync(completed, 500, TimeUnit.MILLISECONDS, function_n, function_s, function_d, function_an, function_nn).get()); + assertEquals(Tuple5.of(n, s, d, anotherN, n + n), thenTupleMApplyMostSuccessAsync(completed, defaultExecutor(), 500, TimeUnit.MILLISECONDS, function_n, function_s, function_d, function_an, function_nn).get()); + } + @Test void test_thenTupleMApplyAsync() throws Exception { final CompletableFuture completed = completedFuture(n); From 926e4369496e6cd7b6f2450af873958caac58514 Mon Sep 17 00:00:00 2001 From: huhaosumail Date: Tue, 25 Jun 2024 20:54:04 +0800 Subject: [PATCH 2/3] =?UTF-8?q?`CffuFactory`=E6=96=B0=E5=A2=9E`Multi-Actio?= =?UTF-8?q?ns(M*)`/`Tuple-Multi-Actions(tupleM*)`=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=E5=8F=8A=E7=9B=B8=E5=85=B3=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/io/foldright/cffu/CffuFactory.java | 280 +++++++++++++++++- .../io/foldright/cffu/CffuFactoryTest.java | 62 ++++ 2 files changed, 335 insertions(+), 7 deletions(-) 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 4ef4700c3..3a00c11c5 100644 --- a/cffu-core/src/main/java/io/foldright/cffu/CffuFactory.java +++ b/cffu-core/src/main/java/io/foldright/cffu/CffuFactory.java @@ -152,7 +152,93 @@ public Cffu runAsync(Runnable action, Executor executor) { // region## Multi-Actions(M*) Methods(create by actions) //////////////////////////////////////////////////////////// - // TODO: TO BE implemented!! + /** + * Returns a new CompletableFuture that is asynchronously completed + * by tasks running in the CompletableFuture's default asynchronous execution facility + * with the values obtained by calling the given Suppliers + * in the same order of the given Suppliers arguments. + *

+ * This method is the same as {@link #mSupplyAsync(Supplier[])} except for the fast-fail behavior. + * + * @param suppliers the suppliers returning the value to be used to complete the returned CompletableFuture + * @param the suppliers' return type + * @return the new CompletableFuture + * @see #allResultsOfFastFail(CompletionStage[]) + * @see CompletableFuture#supplyAsync(Supplier) + */ + public Cffu> mSupplyFastFailAsync(Supplier... suppliers) { + return create(CompletableFutureUtils.mSupplyFastFailAsync(suppliers)); + } + + /** + * Returns a new CompletableFuture that is asynchronously completed + * by tasks running in the CompletableFuture's default asynchronous execution facility + * with the most values obtained by calling the given Suppliers + * in the given time({@code timeout}, aka as many results as possible in the given time) + * in the same order of the given Suppliers arguments. + *

+ * If the given supplier is successful in the given time, the return result is the completed value; + * Otherwise the given valueIfNotSuccess. + * + * @param valueIfNotSuccess the value to return if not completed successfully + * @param timeout how long to wait in units of {@code unit} + * @param unit a {@code TimeUnit} determining how to interpret the {@code timeout} parameter + * @param suppliers the suppliers returning the value to be used to complete the returned CompletableFuture + * @param the suppliers' return type + * @return the new CompletableFuture + * @see #mostResultsOfSuccess(Object, long, TimeUnit, CompletionStage[]) + * @see CompletableFuture#supplyAsync(Supplier) + */ + public Cffu> mSupplyMostSuccessAsync( + @Nullable T valueIfNotSuccess, long timeout, TimeUnit unit, Supplier... suppliers) { + return create(CompletableFutureUtils.mSupplyMostSuccessAsync(valueIfNotSuccess, timeout, unit, suppliers)); + } + + /** + * Returns a new CompletableFuture that is asynchronously completed + * by tasks running in the CompletableFuture's default asynchronous execution facility + * with the values obtained by calling the given Suppliers + * in the same order of the given Suppliers arguments. + * + * @param suppliers the suppliers returning the value to be used to complete the returned CompletableFuture + * @param the suppliers' return type + * @return the new CompletableFuture + * @see #allResultsOf(CompletionStage[]) + * @see CompletableFuture#supplyAsync(Supplier) + */ + public Cffu> mSupplyAsync(Supplier... suppliers) { + return create(CompletableFutureUtils.mSupplyAsync(suppliers)); + } + + /** + * Returns a new CompletableFuture that is asynchronously completed + * by tasks running in the CompletableFuture's default asynchronous execution facility + * after runs the given actions. + *

+ * This method is the same as {@link #mRunAsync(Runnable...)} except for the fast-fail behavior. + * + * @param actions the actions to run before completing the returned CompletableFuture + * @return the new CompletableFuture + * @see #allOfFastFail(CompletionStage[]) + * @see CompletableFuture#runAsync(Runnable) + */ + public Cffu mRunFastFailAsync(Runnable... actions) { + return create(CompletableFutureUtils.mRunFastFailAsync(actions)); + } + + /** + * Returns a new CompletableFuture that is asynchronously completed + * by tasks running in the CompletableFuture's default asynchronous execution facility + * after runs the given actions. + * + * @param actions the actions to run before completing the returned CompletableFuture + * @return the new CompletableFuture + * @see #allOf(CompletionStage[]) + * @see CompletableFuture#runAsync(Runnable) + */ + public Cffu mRunAsync(Runnable... actions) { + return create(CompletableFutureUtils.mRunAsync(actions)); + } // endregion //////////////////////////////////////////////////////////// @@ -174,6 +260,21 @@ public Cffu> tupleMSupplyFastFailAsync( return create(CompletableFutureUtils.tupleMSupplyFastFailAsync(supplier1, supplier2)); } + /** + * Returns a new Cffu that is asynchronously completed + * by tasks running in the {@link #defaultExecutor()} with the values obtained by calling the given Suppliers + * in the same order of the given Suppliers arguments. + *

+ * This method is the same as {@link #tupleMSupplyAsync(Supplier, Supplier)} except for the fast-fail behavior. + * + * @return the new Cffu + * @see #allResultsOfFastFail(CompletionStage[]) + */ + public Cffu> tupleMSupplyFastFailAsync( + Executor executor, Supplier supplier1, Supplier supplier2) { + return create(CompletableFutureUtils.tupleMSupplyFastFailAsync(executor, supplier1, supplier2)); + } + /** * Returns a new Cffu that is asynchronously completed * by tasks running in the {@link #defaultExecutor()} with the values obtained by calling the given Suppliers @@ -189,6 +290,21 @@ public Cffu> tupleMSupplyFastFailAsync( return create(CompletableFutureUtils.tupleMSupplyFastFailAsync(supplier1, supplier2, supplier3)); } + /** + * Returns a new Cffu that is asynchronously completed + * by tasks running in the {@link #defaultExecutor()} with the values obtained by calling the given Suppliers + * in the same order of the given Suppliers arguments. + *

+ * This method is the same as {@link #tupleMSupplyAsync(Supplier, Supplier, Supplier)} except for the fast-fail behavior. + * + * @return the new Cffu + * @see #allResultsOfFastFail(CompletionStage[]) + */ + public Cffu> tupleMSupplyFastFailAsync( + Executor executor, Supplier supplier1, Supplier supplier2, Supplier supplier3) { + return create(CompletableFutureUtils.tupleMSupplyFastFailAsync(executor, supplier1, supplier2, supplier3)); + } + /** * Returns a new Cffu that is asynchronously completed * by tasks running in the {@link #defaultExecutor()} with the values obtained by calling the given Suppliers @@ -205,6 +321,22 @@ public Cffu> tupleMSupplyFastFailAsync( return create(CompletableFutureUtils.tupleMSupplyFastFailAsync(supplier1, supplier2, supplier3, supplier4)); } + /** + * Returns a new Cffu that is asynchronously completed + * by tasks running in the {@link #defaultExecutor()} with the values obtained by calling the given Suppliers + * in the same order of the given Suppliers arguments. + *

+ * This method is the same as {@link #tupleMSupplyAsync(Supplier, Supplier, Supplier, Supplier)} except for the fast-fail behavior. + * + * @return the new Cffu + * @see #allResultsOfFastFail(CompletionStage[]) + */ + public Cffu> tupleMSupplyFastFailAsync( + Executor executor, Supplier supplier1, Supplier supplier2, + Supplier supplier3, Supplier supplier4) { + return create(CompletableFutureUtils.tupleMSupplyFastFailAsync(executor, supplier1, supplier2, supplier3, supplier4)); + } + /** * Returns a new Cffu that is asynchronously completed * by tasks running in the {@link #defaultExecutor()} with the values obtained by calling the given Suppliers @@ -221,6 +353,23 @@ public Cffu> tupleMSupplyFastFai return create(CompletableFutureUtils.tupleMSupplyFastFailAsync(supplier1, supplier2, supplier3, supplier4, supplier5)); } + /** + * Returns a new Cffu that is asynchronously completed + * by tasks running in the {@link #defaultExecutor()} with the values obtained by calling the given Suppliers + * in the same order of the given Suppliers arguments. + *

+ * This method is the same as {@link #tupleMSupplyAsync(Supplier, Supplier, Supplier, Supplier, Supplier)} except for the fast-fail behavior. + * + * @return the new Cffu + * @see #allResultsOfFastFail(CompletionStage[]) + */ + public Cffu> tupleMSupplyFastFailAsync( + Executor executor, Supplier supplier1, Supplier supplier2, Supplier supplier3, + Supplier supplier4, Supplier supplier5) { + return create(CompletableFutureUtils.tupleMSupplyFastFailAsync(executor, supplier1, supplier2, supplier3, supplier4, supplier5)); + } + + /** * Returns a new Cffu that is asynchronously completed * by tasks running in the {@link #defaultExecutor()} with the values obtained by calling the given Suppliers @@ -232,7 +381,22 @@ public Cffu> tupleMSupplyFastFai */ public Cffu> tupleMSupplyMostSuccessAsync( long timeout, TimeUnit unit, Supplier supplier1, Supplier supplier2) { - return create(CompletableFutureUtils.tupleMSupplyMostSuccessAsync(defaultExecutor, timeout, unit, supplier1, supplier2)); + return create(CompletableFutureUtils.tupleMSupplyMostSuccessAsync(timeout, unit, supplier1, supplier2)); + } + + + /** + * Returns a new Cffu that is asynchronously completed + * by tasks running in the {@link #defaultExecutor()} with the values obtained by calling the given Suppliers + * in the same order of the given Suppliers arguments. + *

+ * This method is the same as {@link #tupleMSupplyAsync(Supplier, Supplier)} except for the most-success behavior. + * + * @return the new Cffu + */ + public Cffu> tupleMSupplyMostSuccessAsync(Executor executor, + long timeout, TimeUnit unit, Supplier supplier1, Supplier supplier2) { + return create(CompletableFutureUtils.tupleMSupplyMostSuccessAsync(executor, timeout, unit, supplier1, supplier2)); } /** @@ -248,7 +412,23 @@ public Cffu> tupleMSupplyMostSuccessAsync( long timeout, TimeUnit unit, Supplier supplier1, Supplier supplier2, Supplier supplier3) { return create(CompletableFutureUtils.tupleMSupplyMostSuccessAsync( - defaultExecutor, timeout, unit, supplier1, supplier2, supplier3)); + timeout, unit, supplier1, supplier2, supplier3)); + } + + /** + * Returns a new Cffu that is asynchronously completed + * by tasks running in the {@link #defaultExecutor()} with the values obtained by calling the given Suppliers + * in the same order of the given Suppliers arguments. + *

+ * This method is the same as {@link #tupleMSupplyAsync(Supplier, Supplier)} except for the most-success behavior. + * + * @return the new Cffu + */ + public Cffu> tupleMSupplyMostSuccessAsync( + Executor executor, long timeout, TimeUnit unit, + Supplier supplier1, Supplier supplier2, Supplier supplier3) { + return create(CompletableFutureUtils.tupleMSupplyMostSuccessAsync( + executor, timeout, unit, supplier1, supplier2, supplier3)); } /** @@ -264,7 +444,23 @@ public Cffu> tupleMSupplyMostSuccessAsyn long timeout, TimeUnit unit, Supplier supplier1, Supplier supplier2, Supplier supplier3, Supplier supplier4) { return create(CompletableFutureUtils.tupleMSupplyMostSuccessAsync( - defaultExecutor, timeout, unit, supplier1, supplier2, supplier3, supplier4)); + timeout, unit, supplier1, supplier2, supplier3, supplier4)); + } + + /** + * Returns a new Cffu that is asynchronously completed + * by tasks running in the {@link #defaultExecutor()} with the values obtained by calling the given Suppliers + * in the same order of the given Suppliers arguments. + *

+ * This method is the same as {@link #tupleMSupplyAsync(Supplier, Supplier)} except for the most-success behavior. + * + * @return the new Cffu + */ + public Cffu> tupleMSupplyMostSuccessAsync( + Executor executor, long timeout, TimeUnit unit, Supplier supplier1, Supplier supplier2, + Supplier supplier3, Supplier supplier4) { + return create(CompletableFutureUtils.tupleMSupplyMostSuccessAsync( + executor, timeout, unit, supplier1, supplier2, supplier3, supplier4)); } /** @@ -280,7 +476,23 @@ public Cffu> tupleMSupplyMostSuc long timeout, TimeUnit unit, Supplier supplier1, Supplier supplier2, Supplier supplier3, Supplier supplier4, Supplier supplier5) { return create(CompletableFutureUtils.tupleMSupplyMostSuccessAsync( - defaultExecutor, timeout, unit, supplier1, supplier2, supplier3, supplier4, supplier5)); + timeout, unit, supplier1, supplier2, supplier3, supplier4, supplier5)); + } + + /** + * Returns a new Cffu that is asynchronously completed + * by tasks running in the {@link #defaultExecutor()} with the values obtained by calling the given Suppliers + * in the same order of the given Suppliers arguments. + *

+ * This method is the same as {@link #tupleMSupplyAsync(Supplier, Supplier)} except for the most-success behavior. + * + * @return the new Cffu + */ + public Cffu> tupleMSupplyMostSuccessAsync( + Executor executor, long timeout, TimeUnit unit, Supplier supplier1, Supplier supplier2, + Supplier supplier3, Supplier supplier4, Supplier supplier5) { + return create(CompletableFutureUtils.tupleMSupplyMostSuccessAsync( + executor, timeout, unit, supplier1, supplier2, supplier3, supplier4, supplier5)); } /** @@ -296,6 +508,19 @@ public Cffu> tupleMSupplyAsync( return create(CompletableFutureUtils.tupleMSupplyAsync(supplier1, supplier2)); } + /** + * Returns a new Cffu that is asynchronously completed + * by tasks running in the {@link #defaultExecutor()} with the values obtained by calling the given Suppliers + * in the same order of the given Suppliers arguments. + * + * @return the new Cffu + * @see #allResultsOf(CompletionStage[]) + */ + public Cffu> tupleMSupplyAsync( + Executor executor, Supplier supplier1, Supplier supplier2) { + return create(CompletableFutureUtils.tupleMSupplyAsync(executor, supplier1, supplier2)); + } + /** * Returns a new Cffu that is asynchronously completed * by tasks running in the {@link #defaultExecutor()} with the values obtained by calling the given Suppliers @@ -309,6 +534,19 @@ public Cffu> tupleMSupplyAsync( return create(CompletableFutureUtils.tupleMSupplyAsync(supplier1, supplier2, supplier3)); } + /** + * Returns a new Cffu that is asynchronously completed + * by tasks running in the {@link #defaultExecutor()} with the values obtained by calling the given Suppliers + * in the same order of the given Suppliers arguments. + * + * @return the new Cffu + * @see #allResultsOf(CompletionStage[]) + */ + public Cffu> tupleMSupplyAsync( + Executor executor, Supplier supplier1, Supplier supplier2, Supplier supplier3) { + return create(CompletableFutureUtils.tupleMSupplyAsync(executor, supplier1, supplier2, supplier3)); + } + /** * Returns a new Cffu that is asynchronously completed * by tasks running in the {@link #defaultExecutor()} with the values obtained by calling the given Suppliers @@ -323,6 +561,21 @@ public Cffu> tupleMSupplyAsync( return create(CompletableFutureUtils.tupleMSupplyAsync(supplier1, supplier2, supplier3, supplier4)); } + /** + * Returns a new Cffu that is asynchronously completed + * by tasks running in the {@link #defaultExecutor()} with the values obtained by calling the given Suppliers + * in the same order of the given Suppliers arguments. + * + * @return the new Cffu + * @see #allResultsOf(CompletionStage[]) + */ + public Cffu> tupleMSupplyAsync( + Executor executor, + Supplier supplier1, Supplier supplier2, + Supplier supplier3, Supplier supplier4) { + return create(CompletableFutureUtils.tupleMSupplyAsync(executor, supplier1, supplier2, supplier3, supplier4)); + } + /** * Returns a new Cffu that is asynchronously completed * by tasks running in the {@link #defaultExecutor()} with the values obtained by calling the given Suppliers @@ -337,6 +590,20 @@ public Cffu> tupleMSupplyAsync( return create(CompletableFutureUtils.tupleMSupplyAsync(supplier1, supplier2, supplier3, supplier4, supplier5)); } + /** + * Returns a new Cffu that is asynchronously completed + * by tasks running in the {@link #defaultExecutor()} with the values obtained by calling the given Suppliers + * in the same order of the given Suppliers arguments. + * + * @return the new Cffu + * @see #allResultsOf(CompletionStage[]) + */ + public Cffu> tupleMSupplyAsync( + Executor executor, Supplier supplier1, Supplier supplier2, + Supplier supplier3, Supplier supplier4, Supplier supplier5) { + return create(CompletableFutureUtils.tupleMSupplyAsync(supplier1, supplier2, supplier3, supplier4, supplier5)); + } + // endregion //////////////////////////////////////////////////////////////////////////////// // region## allOf* Methods(including mostResultsOfSuccess) @@ -913,8 +1180,7 @@ public static CompletableFuture[] cffuArrayUnwrap(Cffu... cfs) { */ @Contract(pure = true) public static Cffu[] cffuListToArray(List> cffuList) { - @SuppressWarnings("unchecked") - final Cffu[] a = new Cffu[cffuList.size()]; + @SuppressWarnings("unchecked") final Cffu[] a = new Cffu[cffuList.size()]; return cffuList.toArray(a); } diff --git a/cffu-core/src/test/java/io/foldright/cffu/CffuFactoryTest.java b/cffu-core/src/test/java/io/foldright/cffu/CffuFactoryTest.java index ffd4f6197..0916f819d 100644 --- a/cffu-core/src/test/java/io/foldright/cffu/CffuFactoryTest.java +++ b/cffu-core/src/test/java/io/foldright/cffu/CffuFactoryTest.java @@ -13,10 +13,16 @@ import java.util.Arrays; import java.util.Collections; +import java.util.List; import java.util.concurrent.*; import java.util.function.Supplier; import static io.foldright.cffu.CompletableFutureUtils.failedFuture; +import static io.foldright.cffu.CompletableFutureUtils.mRunAsync; +import static io.foldright.cffu.CompletableFutureUtils.mRunFastFailAsync; +import static io.foldright.cffu.CompletableFutureUtils.mSupplyAsync; +import static io.foldright.cffu.CompletableFutureUtils.mSupplyFastFailAsync; +import static io.foldright.cffu.CompletableFutureUtils.mSupplyMostSuccessAsync; import static io.foldright.cffu.CompletableFutureUtils.toCompletableFutureArray; import static io.foldright.test_utils.TestUtils.*; import static java.util.concurrent.CompletableFuture.completedFuture; @@ -30,6 +36,50 @@ */ @SuppressWarnings("RedundantThrows") class CffuFactoryTest { + + //////////////////////////////////////////////////////////////////////////////// + //# multi-actions(M*) methods + //////////////////////////////////////////////////////////////////////////////// + + @Test + void test_mRun() throws Exception { + final Runnable runnable = () -> sleep(100); + + final long tick = System.currentTimeMillis(); + @SuppressWarnings("unchecked") + Cffu[] cfs = new Cffu[]{ + cffuFactory.mRunAsync(runnable, runnable), + cffuFactory.mRunFastFailAsync(runnable, runnable) + }; + + assertTrue(System.currentTimeMillis() - tick < 50); + for (Cffu cf : cfs) { + assertNull(cf.get()); + } + } + + @Test + void test_mSupply() throws Exception { + final Supplier supplier = () -> { + sleep(100); + return n; + }; + + final long tick = System.currentTimeMillis(); + + @SuppressWarnings("unchecked") + Cffu>[] cfs = new Cffu[]{ + cffuFactory.mSupplyAsync(supplier, supplier), + cffuFactory.mSupplyFastFailAsync(supplier, supplier), + cffuFactory.mSupplyMostSuccessAsync(anotherN, 500, TimeUnit.MILLISECONDS, supplier, supplier) + }; + + assertTrue(System.currentTimeMillis() - tick < 50); + for (Cffu> cf : cfs) { + assertEquals(Arrays.asList(n, n), cf.get()); + } + } + /////////////////////////////////////////////////////////////////////////////// //# Factory Methods, equivalent to same name static methods of CompletableFuture // @@ -649,16 +699,24 @@ void test_tupleMSupplyAsync() throws Exception { return n + n; }; assertEquals(Tuple2.of(n, s), cffuFactory.tupleMSupplyAsync(supplier_n, supplier_s).get()); + assertEquals(Tuple2.of(n, s), cffuFactory.tupleMSupplyAsync(executorService, supplier_n, supplier_s).get()); assertEquals(Tuple2.of(n, s), cffuFactory.tupleMSupplyFastFailAsync(supplier_n, supplier_s).get()); + assertEquals(Tuple2.of(n, s), cffuFactory.tupleMSupplyFastFailAsync(executorService, supplier_n, supplier_s).get()); assertEquals(Tuple3.of(n, s, d), cffuFactory.tupleMSupplyAsync(supplier_n, supplier_s, supplier_d).get()); + assertEquals(Tuple3.of(n, s, d), cffuFactory.tupleMSupplyAsync(executorService, supplier_n, supplier_s, supplier_d).get()); assertEquals(Tuple3.of(n, s, d), cffuFactory.tupleMSupplyFastFailAsync(supplier_n, supplier_s, supplier_d).get()); + assertEquals(Tuple3.of(n, s, d), cffuFactory.tupleMSupplyFastFailAsync(executorService, supplier_n, supplier_s, supplier_d).get()); assertEquals(Tuple4.of(n, s, d, anotherN), cffuFactory.tupleMSupplyAsync(supplier_n, supplier_s, supplier_d, supplier_an).get()); + assertEquals(Tuple4.of(n, s, d, anotherN), cffuFactory.tupleMSupplyAsync(executorService, supplier_n, supplier_s, supplier_d, supplier_an).get()); assertEquals(Tuple4.of(n, s, d, anotherN), cffuFactory.tupleMSupplyFastFailAsync(supplier_n, supplier_s, supplier_d, supplier_an).get()); + assertEquals(Tuple4.of(n, s, d, anotherN), cffuFactory.tupleMSupplyFastFailAsync(executorService, supplier_n, supplier_s, supplier_d, supplier_an).get()); assertEquals(Tuple5.of(n, s, d, anotherN, n + n), cffuFactory.tupleMSupplyAsync(supplier_n, supplier_s, supplier_d, supplier_an, supplier_nn).get()); + assertEquals(Tuple5.of(n, s, d, anotherN, n + n), cffuFactory.tupleMSupplyAsync(executorService, supplier_n, supplier_s, supplier_d, supplier_an, supplier_nn).get()); assertEquals(Tuple5.of(n, s, d, anotherN, n + n), cffuFactory.tupleMSupplyFastFailAsync(supplier_n, supplier_s, supplier_d, supplier_an, supplier_nn).get()); + assertEquals(Tuple5.of(n, s, d, anotherN, n + n), cffuFactory.tupleMSupplyFastFailAsync(executorService, supplier_n, supplier_s, supplier_d, supplier_an, supplier_nn).get()); } @Test @@ -685,12 +743,16 @@ void test_tupleMSupplyMostSuccessAsync() throws Exception { return n + n; }; assertEquals(Tuple2.of(n, s), cffuFactory.tupleMSupplyMostSuccessAsync(100, TimeUnit.MILLISECONDS, supplier_n, supplier_s).get()); + assertEquals(Tuple2.of(n, s), cffuFactory.tupleMSupplyMostSuccessAsync(executorService, 100, TimeUnit.MILLISECONDS, supplier_n, supplier_s).get()); assertEquals(Tuple3.of(n, s, d), cffuFactory.tupleMSupplyMostSuccessAsync(100, TimeUnit.MILLISECONDS, supplier_n, supplier_s, supplier_d).get()); + assertEquals(Tuple3.of(n, s, d), cffuFactory.tupleMSupplyMostSuccessAsync(executorService, 100, TimeUnit.MILLISECONDS, supplier_n, supplier_s, supplier_d).get()); assertEquals(Tuple4.of(n, s, d, anotherN), cffuFactory.tupleMSupplyMostSuccessAsync(100, TimeUnit.MILLISECONDS, supplier_n, supplier_s, supplier_d, supplier_an).get()); + assertEquals(Tuple4.of(n, s, d, anotherN), cffuFactory.tupleMSupplyMostSuccessAsync(executorService, 100, TimeUnit.MILLISECONDS, supplier_n, supplier_s, supplier_d, supplier_an).get()); assertEquals(Tuple5.of(n, s, d, anotherN, n + n), cffuFactory.tupleMSupplyMostSuccessAsync(100, TimeUnit.MILLISECONDS, supplier_n, supplier_s, supplier_d, supplier_an, supplier_nn).get()); + assertEquals(Tuple5.of(n, s, d, anotherN, n + n), cffuFactory.tupleMSupplyMostSuccessAsync(executorService, 100, TimeUnit.MILLISECONDS, supplier_n, supplier_s, supplier_d, supplier_an, supplier_nn).get()); } //////////////////////////////////////////////////////////////////////////////// From 9f0210695cc92e6885becd781a4fc21f624e424c Mon Sep 17 00:00:00 2001 From: huhaosumail Date: Wed, 26 Jun 2024 22:23:52 +0800 Subject: [PATCH 3/3] =?UTF-8?q?`Cffu`=E6=96=B0=E5=A2=9E`Then-Multi-Actions?= =?UTF-8?q?(thenM*)`/`thenTupleMApplyMostSuccessAsync`=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=E5=8F=8A=E7=9B=B8=E5=85=B3=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/io/foldright/cffu/Cffu.java | 369 +++++++++++++++++- .../test/java/io/foldright/cffu/CffuTest.java | 110 +++++- 2 files changed, 473 insertions(+), 6 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 afab1116c..aca4be495 100644 --- a/cffu-core/src/main/java/io/foldright/cffu/Cffu.java +++ b/cffu-core/src/main/java/io/foldright/cffu/Cffu.java @@ -10,6 +10,7 @@ import org.jetbrains.annotations.Blocking; import org.jetbrains.annotations.Contract; +import java.util.List; import java.util.concurrent.*; import java.util.function.*; @@ -210,7 +211,236 @@ public Cffu thenRunAsync(Runnable action, Executor executor) { // region## Then-Multi-Actions(thenM*) Methods //////////////////////////////////////////////////////////// - // TODO: TO BE implemented!! + /** + * Returns a new Cffu that, when the given stage completes normally, + * is executed using the CompletableFuture's default asynchronous execution facility, + * with the values obtained by calling the given Functions + * (with the given stage's result as the argument to the given functions) + * in the same order of the given Functions arguments. + *

+ * This method is the same as {@link #thenMApplyAsync(CompletionStage, Function[])} + * except for the fast-fail behavior. + * + * @param fns the functions to use to compute the values of the returned Cffu + * @param the functions' return type + * @return the new Cffu + */ + public Cffu> thenMApplyFastFailAsync( + CompletionStage cf, Function... fns) { + return thenMApplyFastFailAsync(cf,fac.defaultExecutor(),fns); + } + + /** + * Returns a new Cffu that, when the given stage completes normally, + * is executed using the given Executor, with the values obtained by calling the given Functions + * (with the given stage's result as the argument to the given functions) + * in the same order of the given Functions arguments. + *

+ * This method is the same as {@link #thenMApplyAsync(CompletionStage, Executor, Function[])} + * except for the fast-fail behavior. + * + * @param fns the functions to use to compute the values of the returned Cffu + * @param executor executor + * @param the functions' return type + * @return the new Cffu + */ + public Cffu> thenMApplyFastFailAsync( + CompletionStage cf, Executor executor, Function... fns) { + return reset0(CompletableFutureUtils.thenMApplyFastFailAsync(cf, executor, fns)); + } + + /** + * Returns a new Cffu that, when the given stage completes normally, + * is executed using the CompletableFuture's default asynchronous execution facility, + * with the most values obtained by calling the given Functions + * (with the given stage's result as the argument to the given functions) + * in the given time({@code timeout}, aka as many results as possible in the given time) + * in the same order of the given Functions arguments. + *

+ * If the given function is successful in the given time, the return result is the completed value; + * Otherwise the given valueIfNotSuccess. + * + * @param valueIfNotSuccess the value to return if not completed successfully + * @param timeout how long to wait in units of {@code unit} + * @param unit a {@code TimeUnit} determining how to interpret the {@code timeout} parameter + * @param fns the functions to use to compute the values of the returned Cffu + * @param the functions' return type + * @return the new Cffu + */ + public Cffu> thenMApplyMostSuccessAsync( + CompletionStage cf, @Nullable U valueIfNotSuccess, + long timeout, TimeUnit unit, Function... fns) { + return thenMApplyMostSuccessAsync(cf, valueIfNotSuccess, fac.defaultExecutor(),timeout, unit, fns); + } + + /** + * Returns a new Cffu that, when the given stage completes normally, + * is executed using the given Executor, with the most values obtained by calling the given Functions + * (with the given stage's result as the argument to the given functions) + * in the given time({@code timeout}, aka as many results as possible in the given time) + * in the same order of the given Functions arguments. + *

+ * If the given function is successful in the given time, the return result is the completed value; + * Otherwise the given valueIfNotSuccess. + * + * @param valueIfNotSuccess the value to return if not completed successfully + * @param executor the executor to use for asynchronous execution + * @param timeout how long to wait in units of {@code unit} + * @param unit a {@code TimeUnit} determining how to interpret the {@code timeout} parameter + * @param fns the functions to use to compute the values of the returned Cffu + * @param the functions' return type + * @return the new Cffu + */ + public Cffu> thenMApplyMostSuccessAsync( + CompletionStage cf, @Nullable U valueIfNotSuccess, + Executor executor, long timeout, TimeUnit unit, Function... fns) { + return reset0(CompletableFutureUtils.thenMApplyMostSuccessAsync(cf, valueIfNotSuccess, executor, timeout, unit, fns)); + } + + /** + * Returns a new Cffu that, when the given stage completes normally, + * is executed using the CompletableFuture's default asynchronous execution facility, + * with the values obtained by calling the given Functions + * (with the given stage's result as the argument to the given functions) + * in the same order of the given Functions arguments. + * + * @param fns the functions to use to compute the values of the returned Cffu + * @param the functions' return type + * @return the new Cffu + */ + public Cffu> thenMApplyAsync( + CompletionStage cf, Function... fns) { + return thenMApplyAsync(cf,fac.defaultExecutor(), fns); + } + + /** + * Returns a new Cffu that, when the given stage completes normally, + * is executed using the given Executor, with the values obtained by calling the given Functions + * (with the given stage's result as the argument to the given functions) + * in the same order of the given Functions arguments. + * + * @param fns the functions to use to compute the values of the returned Cffu + * @param the functions' return type + * @return the new Cffu + */ + public Cffu> thenMApplyAsync( + CompletionStage cf, Executor executor, Function... fns) { + return reset0(CompletableFutureUtils.thenMApplyAsync(cf, executor, fns)); + } + + + /** + * Returns a new Cffu that, when the given stage completes normally, + * is executed using the CompletableFuture's default asynchronous execution facility, + * with the given stage's result as the argument to the given actions. + * + * @param actions the actions to perform before completing the returned Cffu + * @return the new Cffu + */ + public Cffu thenMAcceptAsync( + CompletionStage cf, Consumer... actions) { + return thenMAcceptAsync(cf,fac.defaultExecutor(), actions); + } + + /** + * Returns a new Cffu that, when the given stage completes normally, + * is executed using the given Executor, with the given stage's result as the argument to the given actions. + * + * @param actions the actions to perform before completing the returned Cffu + * @return the new Cffu + */ + public Cffu thenMAcceptAsync( + CompletionStage cf, Executor executor, Consumer... actions) { + return reset0(CompletableFutureUtils.thenMAcceptAsync(cf, executor, actions)); + } + + /** + * Returns a new Cffu that, when the given stage completes normally, + * is executed using the CompletableFuture's default asynchronous execution facility, + * with the given stage's result as the argument to the given actions. + *

+ * This method is the same as {@link #thenMAcceptAsync(CompletionStage, Consumer[])} + * except for the fast-fail behavior. + * + * @param actions the actions to perform before completing the returned Cffu + * @return the new Cffu + */ + public Cffu thenMAcceptFastFailAsync( + CompletionStage cf, Consumer... actions) { + return thenMAcceptFastFailAsync(cf,fac.defaultExecutor(), actions); + } + + /** + * Returns a new Cffu that, when the given stage completes normally, + * is executed using the given Executor, with the given stage's result as the argument to the given actions. + *

+ * This method is the same as {@link #thenMAcceptAsync(CompletionStage, Executor, Consumer[])} + * except for the fast-fail behavior. + * + * @param actions the actions to perform before completing the returned Cffu + * @return the new Cffu + */ + public Cffu thenMAcceptFastFailAsync( + CompletionStage cf, Executor executor, Consumer... actions) { + return reset0(CompletableFutureUtils.thenMAcceptFastFailAsync(cf, executor, actions)); + } + + + /** + * Returns a new Cffu that, when the given stage completes normally, + * executes the given actions using the CompletableFuture's default asynchronous execution facility. + *

+ * This method is the same as {@link #thenMRunAsync(CompletionStage, Runnable...)} + * except for the fast-fail behavior. + * + * @param actions the actions to perform before completing the returned Cffu + * @return the new Cffu + * @see CompletableFuture#thenRunAsync(Runnable) + */ + public Cffu thenMRunFastFailAsync(CompletionStage cf, Runnable... actions) { + return thenMRunFastFailAsync(cf,fac.defaultExecutor(), actions); + } + + /** + * Returns a new Cffu that, when the given stage completes normally, + * executes the given actions using the given Executor. + *

+ * This method is the same as {@link #thenMRunAsync(CompletionStage, Executor, Runnable...)} + * except for the fast-fail behavior. + * + * @param actions the actions to perform before completing the returned Cffu + * @return the new Cffu + * @see CompletableFuture#thenRunAsync(Runnable, Executor) + */ + public Cffu thenMRunFastFailAsync( + CompletionStage cf, Executor executor, Runnable... actions) { + return reset0(CompletableFutureUtils.thenMRunFastFailAsync(cf, executor, actions)); + } + + /** + * Returns a new Cffu that, when the given stage completes normally, + * executes the given actions using the CompletableFuture's default asynchronous execution facility. + * + * @param actions the actions to perform before completing the returned Cffu + * @return the new Cffu + * @see CompletableFuture#thenRunAsync(Runnable) + */ + public Cffu thenMRunAsync(CompletionStage cf, Runnable... actions) { + return thenMRunAsync(cf,fac.defaultExecutor(), actions); + } + + /** + * Returns a new Cffu that, when the given stage completes normally, + * executes the given actions using the given Executor. + * + * @param actions the actions to perform before completing the returned Cffu + * @return the new Cffu + * @see CompletableFuture#thenRunAsync(Runnable, Executor) + */ + public Cffu thenMRunAsync(CompletionStage cf, Executor executor, Runnable... actions) { + return reset0(CompletableFutureUtils.thenMRunAsync(cf, executor, actions)); + } + // endregion //////////////////////////////////////////////////////////// @@ -353,6 +583,143 @@ public Cffu> thenTupleMApplyFast return reset0(CompletableFutureUtils.thenTupleMApplyFastFailAsync(cf, executor, fn1, fn2, fn3, fn4, fn5)); } + + /** + * Returns a new Cffu that, when this Cffu completes normally, is executed using the {@link #defaultExecutor()}, + * with the values obtained by calling the given Functions + * (with this Cffu's result as the argument to the given functions) + * in the same order of the given Functions arguments. + *

+ * This method is the same as {@link #thenTupleMApplyAsync(Function, Function)} + * except for the fast-fail behavior. + * + * @return the new Cffu + */ + public Cffu> thenTupleMApplyMostSuccessAsync( + long timeout, TimeUnit unit, Function fn1, Function fn2) { + return thenTupleMApplyMostSuccessAsync(fac.defaultExecutor(), timeout, unit, fn1, fn2); + } + + /** + * Returns a new Cffu that, when this Cffu completes normally, is executed using the supplied Executor, + * with the values obtained by calling the given Functions + * (with this Cffu's result as the argument to the given functions) + * in the same order of the given Functions arguments. + *

+ * This method is the same as {@link #thenTupleMApplyAsync(Executor, Function, Function)} + * except for the fast-fail behavior. + * + * @return the new Cffu + */ + public Cffu> thenTupleMApplyMostSuccessAsync( + Executor executor, long timeout, TimeUnit unit, Function fn1, Function fn2) { + return reset0(CompletableFutureUtils.thenTupleMApplyMostSuccessAsync(cf, executor, timeout, unit, fn1, fn2)); + } + + /** + * Returns a new Cffu that, when this Cffu completes normally, is executed using the {@link #defaultExecutor()}, + * with the values obtained by calling the given Functions + * (with this Cffu's result as the argument to the given functions) + * in the same order of the given Functions arguments. + *

+ * This method is the same as {@link #thenTupleMApplyAsync(Function, Function, Function)} + * except for the fast-fail behavior. + * + * @return the new Cffu + */ + public Cffu> thenTupleMApplyMostSuccessAsync( + long timeout, TimeUnit unit, Function fn1, + Function fn2, Function fn3) { + return thenTupleMApplyMostSuccessAsync(fac.defaultExecutor(), timeout, unit, fn1, fn2, fn3); + } + + /** + * Returns a new Cffu that, when this Cffu completes normally, is executed using the supplied Executor, + * with the values obtained by calling the given Functions + * (with this Cffu's result as the argument to the given functions) + * in the same order of the given Functions arguments. + *

+ * This method is the same as {@link #thenTupleMApplyAsync(Executor, Function, Function, Function)} + * except for the fast-fail behavior. + * + * @return the new Cffu + */ + public Cffu> thenTupleMApplyMostSuccessAsync( + Executor executor, long timeout, TimeUnit unit, Function fn1, + Function fn2, Function fn3) { + return reset0(CompletableFutureUtils.thenTupleMApplyMostSuccessAsync(cf, executor, timeout, unit, fn1, fn2, fn3)); + } + + /** + * Returns a new Cffu that, when this Cffu completes normally, is executed using the {@link #defaultExecutor()}, + * with the values obtained by calling the given Functions + * (with this Cffu's result as the argument to the given functions) + * in the same order of the given Functions arguments. + *

+ * This method is the same as {@link #thenTupleMApplyAsync(Function, Function, Function, Function)} + * except for the fast-fail behavior. + * + * @return the new Cffu + */ + public Cffu> thenTupleMApplyMostSuccessAsync( + long timeout, TimeUnit unit, Function fn1, Function fn2, + Function fn3, Function fn4) { + return thenTupleMApplyMostSuccessAsync(fac.defaultExecutor(), timeout, unit, fn1, fn2, fn3, fn4); + } + + /** + * Returns a new Cffu that, when this Cffu completes normally, is executed using the supplied Executor, + * with the values obtained by calling the given Functions + * (with this Cffu's result as the argument to the given functions) + * in the same order of the given Functions arguments. + *

+ * This method is the same as {@link #thenTupleMApplyAsync(Executor, Function, Function, Function, Function)} + * except for the fast-fail behavior. + * + * @return the new Cffu + */ + public Cffu> thenTupleMApplyMostSuccessAsync( + Executor executor, long timeout, TimeUnit unit, Function fn1, Function fn2, + Function fn3, Function fn4) { + return reset0(CompletableFutureUtils.thenTupleMApplyMostSuccessAsync(cf, executor, timeout, unit, fn1, fn2, fn3, fn4)); + } + + /** + * Returns a new Cffu that, when this Cffu completes normally, is executed using the {@link #defaultExecutor()}, + * with the values obtained by calling the given Functions + * (with this Cffu's result as the argument to the given functions) + * in the same order of the given Functions arguments. + *

+ * This method is the same as {@link #thenTupleMApplyAsync(Function, Function, Function, Function, Function)} + * except for the fast-fail behavior. + * + * @return the new Cffu + */ + public Cffu> thenTupleMApplyMostSuccessAsync( + long timeout, TimeUnit unit, Function fn1, + Function fn2, Function fn3, + Function fn4, Function fn5) { + return thenTupleMApplyMostSuccessAsync(fac.defaultExecutor(), timeout, unit, fn1, fn2, fn3, fn4, fn5); + } + + /** + * Returns a new Cffu that, when this Cffu completes normally, is executed using the supplied Executor, + * with the values obtained by calling the given Functions + * (with this Cffu's result as the argument to the given functions) + * in the same order of the given Functions arguments. + *

+ * This method is the same as {@link #thenTupleMApplyAsync(Executor, Function, Function, Function, Function, Function)} + * except for the fast-fail behavior. + * + * @return the new Cffu + */ + public Cffu> thenTupleMApplyMostSuccessAsync( + Executor executor, long timeout, TimeUnit unit, Function fn1, + Function fn2, Function fn3, + Function fn4, Function fn5) { + return reset0(CompletableFutureUtils.thenTupleMApplyMostSuccessAsync(cf, executor, timeout, unit, fn1, fn2, fn3, fn4, fn5)); + } + /** * Returns a new Cffu that, when this Cffu completes normally, is executed using the {@link #defaultExecutor()}, * with the values obtained by calling the given Functions diff --git a/cffu-core/src/test/java/io/foldright/cffu/CffuTest.java b/cffu-core/src/test/java/io/foldright/cffu/CffuTest.java index 6d4c641d0..f92293144 100644 --- a/cffu-core/src/test/java/io/foldright/cffu/CffuTest.java +++ b/cffu-core/src/test/java/io/foldright/cffu/CffuTest.java @@ -11,6 +11,8 @@ import org.junit.jupiter.api.condition.EnabledForJreRange; import org.junit.jupiter.api.condition.JRE; +import java.util.Arrays; +import java.util.List; import java.util.concurrent.*; import java.util.function.BiConsumer; import java.util.function.Consumer; @@ -33,42 +35,140 @@ class CffuTest { private static CffuFactory forbidObtrudeMethodsCffuFactory; + //////////////////////////////////////////////////////////////////////////////// + //# multi-actions(M*) methods + //////////////////////////////////////////////////////////////////////////////// + @Test - void test_thenTupleMApplyAsync() throws Exception { + void test_thenMApply() throws Exception { final Cffu completed = cffuFactory.completedFuture(n); + final Function function_n = (x) -> { sleep(100); return n; }; - final Function function_s = (x) -> { + + final long tick = System.currentTimeMillis(); + @SuppressWarnings("unchecked") + Cffu[] cfs = new Cffu[]{ + completed.thenMApplyFastFailAsync(completed, function_n, function_n), + completed.thenMApplyFastFailAsync(completed, executorService, function_n, function_n), + completed.thenMApplyMostSuccessAsync(completed, 100, 500, TimeUnit.MILLISECONDS, function_n, function_n), + completed.thenMApplyMostSuccessAsync(completed, 100, executorService, 500, TimeUnit.MILLISECONDS, function_n, function_n), + completed.thenMApplyAsync(completed, function_n, function_n), + completed.thenMApplyAsync(completed, executorService, function_n, function_n) + }; + + assertTrue(System.currentTimeMillis() - tick < 50); + for (Cffu cf : cfs) { + assertEquals(Arrays.asList(n, n), cf.get()); + } + } + + @Test + void test_thenMAccept() throws Exception { + final Cffu completed = cffuFactory.completedFuture(n); + final Consumer consumer = (x) -> { + assertEquals(n, x); + sleep(100); + }; + + final long tick = System.currentTimeMillis(); + + @SuppressWarnings("unchecked") + Cffu>[] cfs = new Cffu[]{ + completed.thenMAcceptAsync(completed, consumer, consumer), + completed.thenMAcceptAsync(completed, executorService, consumer, consumer), + completed.thenMAcceptFastFailAsync(completed, consumer, consumer), + completed.thenMAcceptFastFailAsync(completed, executorService, consumer, consumer) + }; + + assertTrue(System.currentTimeMillis() - tick < 50); + for (Cffu> cf : cfs) { + assertNull(cf.get()); + } + } + + @Test + void test_thenMRun() throws Exception { + final Cffu completed = cffuFactory.completedFuture(null); + final Runnable runnable = () -> { sleep(100); + }; + + final long tick = System.currentTimeMillis(); + + @SuppressWarnings("unchecked") + Cffu>[] cfs = new Cffu[]{ + completed.thenMRunAsync(completed, runnable, runnable), + completed.thenMRunAsync(completed, executorService, runnable, runnable), + completed.thenMRunFastFailAsync(completed, runnable, runnable), + completed.thenMRunFastFailAsync(completed, executorService, runnable, runnable) + }; + + assertTrue(System.currentTimeMillis() - tick < 50); + for (Cffu> cf : cfs) { + assertNull(cf.get()); + } + } + + //////////////////////////////////////////////////////////////////////////////// + // Then-Tuple-Multi-Actions(thenTupleM*) Methods + //////////////////////////////////////////////////////////////////////////////// + + @Test + void test_thenTupleMApplyAsync() throws Exception { + final Cffu completed = cffuFactory.completedFuture(n); + final Function function_n = (x) -> { + sleep(10); + return n; + }; + + final Function function_s = (x) -> { + sleep(10); return s; }; final Function function_d = (x) -> { - sleep(100); + sleep(10); return d; }; final Function function_an = (x) -> { - sleep(100); + sleep(10); return anotherN; }; final Function function_nn = (x) -> { - sleep(100); + sleep(10); return n + n; }; assertEquals(Tuple2.of(n, s), completed.thenTupleMApplyAsync(function_n, function_s).get()); + assertEquals(Tuple2.of(n, s), completed.thenTupleMApplyAsync(executorService, function_n, function_s).get()); assertEquals(Tuple2.of(n, s), completed.thenTupleMApplyFastFailAsync(function_n, function_s).get()); + assertEquals(Tuple2.of(n, s), completed.thenTupleMApplyFastFailAsync(executorService, function_n, function_s).get()); + assertEquals(Tuple2.of(n, s), completed.thenTupleMApplyMostSuccessAsync(100, TimeUnit.MILLISECONDS, function_n, function_s).get()); + assertEquals(Tuple2.of(n, s), completed.thenTupleMApplyMostSuccessAsync(executorService, 100, TimeUnit.MILLISECONDS, function_n, function_s).get()); assertEquals(Tuple3.of(n, s, d), completed.thenTupleMApplyAsync(function_n, function_s, function_d).get()); + assertEquals(Tuple3.of(n, s, d), completed.thenTupleMApplyAsync(executorService, function_n, function_s, function_d).get()); assertEquals(Tuple3.of(n, s, d), completed.thenTupleMApplyFastFailAsync(function_n, function_s, function_d).get()); + assertEquals(Tuple3.of(n, s, d), completed.thenTupleMApplyFastFailAsync(executorService, function_n, function_s, function_d).get()); + assertEquals(Tuple3.of(n, s, d), completed.thenTupleMApplyMostSuccessAsync(100, TimeUnit.MILLISECONDS, function_n, function_s, function_d).get()); + assertEquals(Tuple3.of(n, s, d), completed.thenTupleMApplyMostSuccessAsync(executorService, 100, TimeUnit.MILLISECONDS, function_n, function_s, function_d).get()); assertEquals(Tuple4.of(n, s, d, anotherN), completed.thenTupleMApplyAsync(function_n, function_s, function_d, function_an).get()); + assertEquals(Tuple4.of(n, s, d, anotherN), completed.thenTupleMApplyAsync(executorService, function_n, function_s, function_d, function_an).get()); assertEquals(Tuple4.of(n, s, d, anotherN), completed.thenTupleMApplyFastFailAsync(function_n, function_s, function_d, function_an).get()); + assertEquals(Tuple4.of(n, s, d, anotherN), completed.thenTupleMApplyFastFailAsync(executorService, function_n, function_s, function_d, function_an).get()); + assertEquals(Tuple4.of(n, s, d, anotherN), completed.thenTupleMApplyMostSuccessAsync(100, TimeUnit.MILLISECONDS, function_n, function_s, function_d, function_an).get()); + assertEquals(Tuple4.of(n, s, d, anotherN), completed.thenTupleMApplyMostSuccessAsync(executorService, 100, TimeUnit.MILLISECONDS, function_n, function_s, function_d, function_an).get()); assertEquals(Tuple5.of(n, s, d, anotherN, n + n), completed.thenTupleMApplyAsync(function_n, function_s, function_d, function_an, function_nn).get()); + assertEquals(Tuple5.of(n, s, d, anotherN, n + n), completed.thenTupleMApplyAsync(executorService, function_n, function_s, function_d, function_an, function_nn).get()); assertEquals(Tuple5.of(n, s, d, anotherN, n + n), completed.thenTupleMApplyFastFailAsync(function_n, function_s, function_d, function_an, function_nn).get()); + assertEquals(Tuple5.of(n, s, d, anotherN, n + n), completed.thenTupleMApplyFastFailAsync(executorService, function_n, function_s, function_d, function_an, function_nn).get()); + assertEquals(Tuple5.of(n, s, d, anotherN, n + n), completed.thenTupleMApplyMostSuccessAsync(100, TimeUnit.MILLISECONDS, function_n, function_s, function_d, function_an, function_nn).get()); + assertEquals(Tuple5.of(n, s, d, anotherN, n + n), completed.thenTupleMApplyMostSuccessAsync(executorService, 100, TimeUnit.MILLISECONDS, function_n, function_s, function_d, function_an, function_nn).get()); } ////////////////////////////////////////////////////////////////////////////////