From c1b7fead70d7b61a8e7136828ec0515c53d2f3cd Mon Sep 17 00:00:00 2001 From: Jerry Lee Date: Mon, 17 Jun 2024 20:23:13 +0800 Subject: [PATCH] WIP --- .editorconfig | 3 + README.md | 24 +- .../src/main/java/io/foldright/cffu/Cffu.java | 524 ++--- .../java/io/foldright/cffu/CffuFactory.java | 545 +++--- .../cffu/CompletableFutureUtils.java | 1719 +++++++++-------- .../java/io/foldright/cffu/CffuStateTest.java | 1 + 6 files changed, 1441 insertions(+), 1375 deletions(-) diff --git a/.editorconfig b/.editorconfig index 6ebf25c7..874706fe 100644 --- a/.editorconfig +++ b/.editorconfig @@ -13,6 +13,9 @@ trim_trailing_whitespace = true ij_any_blank_lines_after_imports = 2 ij_markdown_wrap_text_if_long = false +ij_any_line_comment_add_space = true +ij_any_line_comment_add_space_on_reformat = true +# ij_any_line_comment_at_first_column = true [*.{java,kt}] indent_size = 4 diff --git a/README.md b/README.md index 0ccf1d4f..d1bf8ff2 100644 --- a/README.md +++ b/README.md @@ -64,10 +64,10 @@ - ☘️ **补全业务使用中缺失的功能** - 更方便的功能,如 - - `allResultsOf`方法:返回多个`CF`的结果,而不是无返回结果`Void`(`CompletableFuture#allOf()`) - - `allTupleOf`方法:返回多个`CF`不同类型的结果,而不是同一类型(`allResultsOf`) + - `allResultsOfFastFail`/`allResultsOf`方法:返回多个`CF`的结果,而不是无返回结果`Void`(`CompletableFuture#allOf()`) + - `allTupleOfFastFail`/`allTupleOf`方法:返回多个`CF`不同类型的结果,而不是同一类型(`allResultsOf`) - 更高效灵活的并发执行策略,如 - - `allOfFastFail`方法:有`CF`失败时快速返回,而不再等待所有`CF`运行完成(`allOf`) + - `allResultsOfFastFail`/`allOfFastFail`方法:有`CF`失败时快速返回,而不再等待所有`CF`运行完成(`allOf`) - `anyOfSuccess`方法:返回首个成功的`CF`结果,而不是首个完成(但可能失败)的`CF`(`anyOf`) - `mostResultsOfSuccess`方法:返回指定时间内成功`CF`的结果,忽略失败或还没有运行完成的`CF`(使用缺省值) - 更安全的使用方式,如 @@ -273,10 +273,12 @@ fun main() { ### 2.1 返回多个运行`CF`的结果 -`CompletableFuture`的`allOf`方法没有返回结果,只是返回`Void`,不方便获得所运行的多个`CF`结果。 -\# 需要在`allOf`方法之后再通过入参`CF`的读方法(如`join`/`get)`来获取结果。 +`CompletableFuture`的`allOf`方法没有返回结果,只是返回`Void`。不方便获取所运行的多个`CF`结果: -`cffu`的`allResultsOf`方法提供了返回多个`CF`结果的功能。 +- 需要在`allOf`方法之后再通过入参`CF`的读方法(如`join`/`get)`来获取结果 +- 或是在传入的`Action`设置外部的变量,要注意多线程写的线程安全问题 ⚠️ + +`cffu`的`allResultsOfFastFail`/`allResultsOf`方法提供了返回多个`CF`结果的功能,方便直接也规避了多线程写的线程安全问题。 示例代码如下: @@ -318,7 +320,7 @@ public class AllResultsOfDemo { > \# 完整可运行的Demo代码参见[`AllResultsOfDemo.java`](cffu-core/src/test/java/io/foldright/demo/AllResultsOfDemo.java)。 -上面多个相同结果类型的`CF`,`cffu`还提供了返回多个不同类型`CF`结果的方法,`allTupleOf`方法。 +上面多个相同结果类型的`CF`,`cffu`还提供了返回多个不同类型`CF`结果的方法,`allTupleOfFastFail`/`allTupleOf`方法。 示例代码如下: @@ -414,12 +416,12 @@ public class DefaultExecutorSettingForCffu { > \# 完整可运行的Demo代码参见[`DefaultExecutorSettingForCffu.java`](cffu-core/src/test/java/io/foldright/demo/DefaultExecutorSettingForCffu.java)。 -### 2.3 高效灵活的并发执行策略(`allOfFastFail`/`anyOfSuccess`/`mostResultsOfSuccess`) +### 2.3 高效灵活的并发执行策略(`allResultsOfFastFail`/`anyOfSuccess`/`mostResultsOfSuccess`) - `CompletableFuture`的`allOf`方法会等待所有输入`CF`运行完成;即使有`CF`失败了也要等待后续`CF`运行完成,再返回一个失败的`CF`。 - 对于业务逻辑来说,这样失败且继续等待策略,减慢了业务响应性;会希望如果有输入`CF`失败了,则快速失败不再做于事无补的等待 - - `cffu`提供了相应的`allOfFastFail`/`allResultsOfFastFail`方法 - - `allOf`/`allOfFastFail`两者都是,只有当所有的输入`CF`都成功时,才返回成功结果 + - `cffu`提供了相应的`allResultsOfFastFail`方法 + - `allOf`/`allResultsOfFastFail`两者都是,只有当所有的输入`CF`都成功时,才返回成功结果 - `CompletableFuture`的`anyOf`方法返回首个完成的`CF`(不会等待后续没有完成的`CF`,赛马模式);即使首个完成的`CF`是失败的,也会返回这个失败的`CF`结果。 - 对于业务逻辑来说,会希望赛马模式返回首个成功的`CF`结果,而不是首个完成但失败的`CF` - `cffu`提供了相应的`anyOfSuccess`方法 @@ -450,7 +452,7 @@ public class ConcurrencyStrategyDemo { public static void main(String[] args) throws Exception { //////////////////////////////////////////////////////////////////////// - // CffuFactory#allOfFastFail / allResultsOfFastFail + // CffuFactory#allResultsOfFastFail // CffuFactory#anyOfSuccess //////////////////////////////////////////////////////////////////////// final Cffu successAfterLongTime = cffuFactory.supplyAsync(() -> { 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 eccea0c0..1a89ab70 100644 --- a/cffu-core/src/main/java/io/foldright/cffu/Cffu.java +++ b/cffu-core/src/main/java/io/foldright/cffu/Cffu.java @@ -26,6 +26,10 @@ * @see CompletableFuture */ public final class Cffu implements Future, CompletionStage { + //////////////////////////////////////////////////////////////////////////////// + // region# Internal constructor and fields + //////////////////////////////////////////////////////////////////////////////// + private final CffuFactory fac; private final boolean isMinimalStage; @@ -48,56 +52,71 @@ private CompletionStage resetToMin(CompletableFuture cf) { return new Cffu<>(fac, true, cf); } + // endregion //////////////////////////////////////////////////////////////////////////////// - //# Simple `then*` methods of `CompletionStage`: + // region# Simple then* Methods of CompletionStage // - // - thenRun*(Runnable): Void -> Void - // - thenAccept*(Consumer): T -> Void // - thenApply*(Function): T -> U + // - thenAccept*(Consumer): T -> Void + // - thenRun*(Runnable): Void -> Void //////////////////////////////////////////////////////////////////////////////// /** - * Returns a new Cffu that, when this stage completes normally, executes the given action. + * Returns a new Cffu that, when this stage completes normally, + * is executed with this stage's result as the argument to the supplied function. *

- * See the {@link CompletionStage} documentation for rules covering exceptional completion. + * This method is analogous to {@link java.util.Optional#map Optional.map} and + * {@link java.util.stream.Stream#map Stream.map}. + *

+ * See the {@link CompletionStage} documentation for rules + * covering exceptional completion. * - * @param action the action to perform before completing 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 - * @see CompletionStage#thenRun(Runnable) + * @see CompletionStage#thenApply(Function) */ + @CheckReturnValue(explanation = "should use the returned Cffu; otherwise, prefer method `thenRun`") @Override - public Cffu thenRun(Runnable action) { - return reset0(cf.thenRun(action)); + public Cffu thenApply(Function fn) { + return reset0(cf.thenApply(fn)); } /** * Returns a new Cffu that, when this stage completes normally, - * executes the given action using {@link #defaultExecutor()}. + * is executed using {@link #defaultExecutor()}, + * with this stage's result as the argument to the supplied function. *

* See the {@link CompletionStage} documentation for rules covering exceptional completion. * - * @param action the action to perform before completing 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 - * @see CompletionStage#thenRunAsync(Runnable) + * @see CompletionStage#thenApplyAsync(Function) */ + @CheckReturnValue(explanation = "should use the returned Cffu; otherwise, prefer method `thenRunAsync`") @Override - public Cffu thenRunAsync(Runnable action) { - return thenRunAsync(action, fac.defaultExecutor()); + public Cffu thenApplyAsync(Function fn) { + return thenApplyAsync(fn, fac.defaultExecutor()); } /** * Returns a new Cffu that, when this stage completes normally, - * executes the given action using the supplied Executor. + * is executed using the supplied Executor, + * with this stage's result as the argument to the supplied function. *

* See the {@link CompletionStage} documentation for rules covering exceptional completion. * - * @param action the action to perform before completing 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 - * @see CompletionStage#thenRunAsync(Runnable, Executor) + * @see CompletionStage#thenApplyAsync(Function, Executor) */ + @CheckReturnValue(explanation = "should use the returned Cffu; otherwise, prefer method `thenRunAsync`") @Override - public Cffu thenRunAsync(Runnable action, Executor executor) { - return reset0(cf.thenRunAsync(action, executor)); + public Cffu thenApplyAsync(Function fn, Executor executor) { + return reset0(cf.thenApplyAsync(fn, executor)); } /** @@ -148,169 +167,183 @@ public Cffu thenAcceptAsync(Consumer action, Executor executor) } /** - * Returns a new Cffu that, when this stage completes normally, - * is executed with this stage's result as the argument to the supplied function. - *

- * This method is analogous to {@link java.util.Optional#map Optional.map} and - * {@link java.util.stream.Stream#map Stream.map}. + * Returns a new Cffu that, when this stage completes normally, executes the given action. *

- * See the {@link CompletionStage} documentation for rules - * covering exceptional completion. + * See the {@link CompletionStage} documentation for rules covering exceptional completion. * - * @param fn the function to use to compute the value of the returned Cffu - * @param the function's return type + * @param action the action to perform before completing the returned Cffu * @return the new Cffu - * @see CompletionStage#thenApply(Function) + * @see CompletionStage#thenRun(Runnable) */ - @CheckReturnValue(explanation = "should use the returned Cffu; otherwise, prefer method `thenRun`") @Override - public Cffu thenApply(Function fn) { - return reset0(cf.thenApply(fn)); + public Cffu thenRun(Runnable action) { + return reset0(cf.thenRun(action)); } /** * Returns a new Cffu that, when this stage completes normally, - * is executed using {@link #defaultExecutor()}, - * with this stage's result as the argument to the supplied function. + * executes the given action using {@link #defaultExecutor()}. *

* See the {@link CompletionStage} documentation for rules covering exceptional completion. * - * @param fn the function to use to compute the value of the returned Cffu - * @param the function's return type + * @param action the action to perform before completing the returned Cffu * @return the new Cffu - * @see CompletionStage#thenApplyAsync(Function) + * @see CompletionStage#thenRunAsync(Runnable) */ - @CheckReturnValue(explanation = "should use the returned Cffu; otherwise, prefer method `thenRunAsync`") @Override - public Cffu thenApplyAsync(Function fn) { - return thenApplyAsync(fn, fac.defaultExecutor()); + public Cffu thenRunAsync(Runnable action) { + return thenRunAsync(action, fac.defaultExecutor()); } /** * Returns a new Cffu that, when this stage completes normally, - * is executed using the supplied Executor, - * with this stage's result as the argument to the supplied function. + * executes the given action using the supplied Executor. *

* See the {@link CompletionStage} documentation for rules covering exceptional completion. * - * @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 + * @param action the action to perform before completing the returned Cffu * @return the new Cffu - * @see CompletionStage#thenApplyAsync(Function, Executor) + * @see CompletionStage#thenRunAsync(Runnable, Executor) */ - @CheckReturnValue(explanation = "should use the returned Cffu; otherwise, prefer method `thenRunAsync`") @Override - public Cffu thenApplyAsync(Function fn, Executor executor) { - return reset0(cf.thenApplyAsync(fn, executor)); + public Cffu thenRunAsync(Runnable action, Executor executor) { + return reset0(cf.thenRunAsync(action, executor)); } + // endregion //////////////////////////////////////////////////////////////////////////////// - //# `then both(binary input)` methods of CompletionStage: + // region# thenBoth* Methods(binary input) of CompletionStage // - // - runAfterBoth*(Runnable): Void, Void -> Void - // - thenAcceptBoth*(BiConsumer): (T1, T2) -> Void // - thenCombine*(BiFunction): (T1, T2) -> U + // - thenAcceptBoth*(BiConsumer): (T1, T2) -> Void + // - runAfterBoth*(Runnable): Void, Void -> Void //////////////////////////////////////////////////////////////////////////////// /** - * Returns a new Cffu that, when this and the other given stage both complete normally, executes the given action. + * Returns a new Cffu that, when this and the other given stage both complete normally, + * is executed with the two results as arguments to the supplied function. *

* See the {@link CompletionStage} documentation for rules covering exceptional completion. * - * @param other the other CompletionStage - * @param action the action to perform before completing the returned Cffu + * @param other the other CompletionStage + * @param fn the function to use to compute the value of the returned Cffu + * @param the type of the other CompletionStage's result + * @param the function's return type * @return the new Cffu */ + @CheckReturnValue(explanation = "should use the returned Cffu; otherwise, prefer method `thenAcceptBoth`") @Override - public Cffu runAfterBoth(CompletionStage other, Runnable action) { - return reset0(cf.runAfterBoth(other, action)); + public Cffu thenCombine( + CompletionStage other, BiFunction fn) { + return reset0(cf.thenCombine(other, fn)); } /** * Returns a new Cffu that, when this and the other given stage both complete normally, - * executes the given action using {@link #defaultExecutor()}. + * is executed using {@link #defaultExecutor()}, with the two results as arguments to the supplied function. *

- * See the {@link CompletionStage} documentation for rules - * covering exceptional completion. + * See the {@link CompletionStage} documentation for rules covering exceptional completion. * - * @param other the other CompletionStage - * @param action the action to perform before completing the returned Cffu + * @param other the other CompletionStage + * @param fn the function to use to compute the value of the returned Cffu + * @param the type of the other CompletionStage's result + * @param the function's return type * @return the new Cffu */ + @CheckReturnValue(explanation = "should use the returned Cffu; otherwise, prefer method `thenAcceptBothAsync`") @Override - public Cffu runAfterBothAsync(CompletionStage other, Runnable action) { - return runAfterBothAsync(other, action, fac.defaultExecutor()); + public Cffu thenCombineAsync( + CompletionStage other, BiFunction fn) { + return thenCombineAsync(other, fn, fac.defaultExecutor()); } /** * Returns a new Cffu that, when this and the other given stage both complete normally, - * executes the given action using the supplied executor. + * is executed using the supplied executor, with the two results as arguments to the supplied function. *

* See the {@link CompletionStage} documentation for rules covering exceptional completion. * * @param other the other CompletionStage - * @param action the action to perform before completing 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 type of the other CompletionStage's result + * @param the function's return type * @return the new Cffu */ + @CheckReturnValue(explanation = "should use the returned Cffu; otherwise, prefer method `thenAcceptBothAsync`") @Override - public Cffu runAfterBothAsync(CompletionStage other, Runnable action, Executor executor) { - return reset0(cf.runAfterBothAsync(other, action, executor)); + public Cffu thenCombineAsync(CompletionStage other, + BiFunction fn, + Executor executor) { + return reset0(cf.thenCombineAsync(other, fn, executor)); } /** - * Returns a new Cffu that, when this and the other given stage both complete normally, executes the given action. + * Returns a new Cffu that, when this and the other given stage both complete normally, + * is executed with the two results as arguments to the supplied function. * if any of the given stage complete exceptionally, then the returned Cffu also does so * *without* waiting other incomplete given CompletionStage, * with a CompletionException holding this exception as its cause. *

- * This method is the same as {@link #runAfterBoth(CompletionStage, Runnable)} + * This method is the same as {@link #thenCombine(CompletionStage, BiFunction)} * except for the fast-fail behavior. * - * @param other the other CompletionStage - * @param action the action to perform before completing the returned Cffu + * @param other the other CompletionStage + * @param fn the function to use to compute the value of the returned Cffu + * @param the type of the other CompletionStage's result + * @param the function's return type * @return the new Cffu */ - public Cffu runAfterBothFastFail(CompletionStage other, Runnable action) { - return reset0(CompletableFutureUtils.runAfterBothFastFail(this, other, action)); + @CheckReturnValue(explanation = "should use the returned Cffu; otherwise, prefer method `thenAcceptBothFastFail`") + public Cffu thenCombineFastFail( + CompletionStage other, BiFunction fn) { + return reset0(CompletableFutureUtils.thenCombineFastFail(this, other, fn)); } /** * Returns a new Cffu that, when this and the other given stage both complete normally, - * executes the given action using {@link #defaultExecutor()}. + * is executed using {@link #defaultExecutor()}, with the two results as arguments to the supplied function. * if any of the given stage complete exceptionally, then the returned Cffu also does so * *without* waiting other incomplete given CompletionStage, * with a CompletionException holding this exception as its cause. *

- * This method is the same as {@link #runAfterBothAsync(CompletionStage, Runnable)} + * This method is the same as {@link #thenCombineAsync(CompletionStage, BiFunction)} * except for the fast-fail behavior. * - * @param other the other CompletionStage - * @param action the action to perform before completing the returned Cffu + * @param other the other CompletionStage + * @param fn the function to use to compute the value of the returned Cffu + * @param the type of the other CompletionStage's result + * @param the function's return type * @return the new Cffu */ - public Cffu runAfterBothFastFailAsync(CompletionStage other, Runnable action) { - return runAfterBothFastFailAsync(other, action, fac.defaultExecutor()); + @CheckReturnValue(explanation = "should use the returned Cffu; otherwise, prefer method `thenAcceptBothFastFailAsync`") + public Cffu thenCombineFastFailAsync( + CompletionStage other, BiFunction fn) { + return thenCombineFastFailAsync(other, fn, fac.defaultExecutor()); } /** * Returns a new Cffu that, when this and the other given stage both complete normally, - * executes the given action using the supplied executor. + * is executed using the supplied executor, with the two results as arguments to the supplied function. * if any of the given stage complete exceptionally, then the returned Cffu also does so * *without* waiting other incomplete given CompletionStage, * with a CompletionException holding this exception as its cause. *

- * This method is the same as {@link #runAfterBothAsync(CompletionStage, Runnable, Executor)} + * This method is the same as {@link #thenCombineAsync(CompletionStage, BiFunction, Executor)} * except for the fast-fail behavior. * * @param other the other CompletionStage - * @param action the action to perform before completing 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 type of the other CompletionStage's result + * @param the function's return type * @return the new Cffu */ - public Cffu runAfterBothFastFailAsync(CompletionStage other, Runnable action, Executor executor) { - return reset0(CompletableFutureUtils.runAfterBothFastFailAsync(this, other, action, executor)); + @CheckReturnValue(explanation = "should use the returned Cffu; otherwise, prefer method `thenAcceptBothFastFailAsync`") + public Cffu thenCombineFastFailAsync(CompletionStage other, + BiFunction fn, + Executor executor) { + return reset0(CompletableFutureUtils.thenCombineFastFailAsync(this, other, fn, executor)); } /** @@ -430,237 +463,226 @@ public Cffu thenAcceptBothFastFailAsync(CompletionStage o } /** - * Returns a new Cffu that, when this and the other given stage both complete normally, - * is executed with the two results as arguments to the supplied function. + * Returns a new Cffu that, when this and the other given stage both complete normally, executes the given action. *

* See the {@link CompletionStage} documentation for rules covering exceptional completion. * - * @param other the other CompletionStage - * @param fn the function to use to compute the value of the returned Cffu - * @param the type of the other CompletionStage's result - * @param the function's return type + * @param other the other CompletionStage + * @param action the action to perform before completing the returned Cffu * @return the new Cffu */ - @CheckReturnValue(explanation = "should use the returned Cffu; otherwise, prefer method `thenAcceptBoth`") @Override - public Cffu thenCombine( - CompletionStage other, BiFunction fn) { - return reset0(cf.thenCombine(other, fn)); + public Cffu runAfterBoth(CompletionStage other, Runnable action) { + return reset0(cf.runAfterBoth(other, action)); } /** * Returns a new Cffu that, when this and the other given stage both complete normally, - * is executed using {@link #defaultExecutor()}, with the two results as arguments to the supplied function. + * executes the given action using {@link #defaultExecutor()}. *

- * See the {@link CompletionStage} documentation for rules covering exceptional completion. + * See the {@link CompletionStage} documentation for rules + * covering exceptional completion. * - * @param other the other CompletionStage - * @param fn the function to use to compute the value of the returned Cffu - * @param the type of the other CompletionStage's result - * @param the function's return type + * @param other the other CompletionStage + * @param action the action to perform before completing the returned Cffu * @return the new Cffu */ - @CheckReturnValue(explanation = "should use the returned Cffu; otherwise, prefer method `thenAcceptBothAsync`") @Override - public Cffu thenCombineAsync( - CompletionStage other, BiFunction fn) { - return thenCombineAsync(other, fn, fac.defaultExecutor()); + public Cffu runAfterBothAsync(CompletionStage other, Runnable action) { + return runAfterBothAsync(other, action, fac.defaultExecutor()); } /** * Returns a new Cffu that, when this and the other given stage both complete normally, - * is executed using the supplied executor, with the two results as arguments to the supplied function. + * executes the given action using the supplied executor. *

* See the {@link CompletionStage} documentation for rules covering exceptional completion. * * @param other the other CompletionStage - * @param fn the function to use to compute the value of the returned Cffu + * @param action the action to perform before completing the returned Cffu * @param executor the executor to use for asynchronous execution - * @param the type of the other CompletionStage's result - * @param the function's return type * @return the new Cffu */ - @CheckReturnValue(explanation = "should use the returned Cffu; otherwise, prefer method `thenAcceptBothAsync`") @Override - public Cffu thenCombineAsync(CompletionStage other, - BiFunction fn, - Executor executor) { - return reset0(cf.thenCombineAsync(other, fn, executor)); + public Cffu runAfterBothAsync(CompletionStage other, Runnable action, Executor executor) { + return reset0(cf.runAfterBothAsync(other, action, executor)); } /** - * Returns a new Cffu that, when this and the other given stage both complete normally, - * is executed with the two results as arguments to the supplied function. + * Returns a new Cffu that, when this and the other given stage both complete normally, executes the given action. * if any of the given stage complete exceptionally, then the returned Cffu also does so * *without* waiting other incomplete given CompletionStage, * with a CompletionException holding this exception as its cause. *

- * This method is the same as {@link #thenCombine(CompletionStage, BiFunction)} + * This method is the same as {@link #runAfterBoth(CompletionStage, Runnable)} * except for the fast-fail behavior. * - * @param other the other CompletionStage - * @param fn the function to use to compute the value of the returned Cffu - * @param the type of the other CompletionStage's result - * @param the function's return type + * @param other the other CompletionStage + * @param action the action to perform before completing the returned Cffu * @return the new Cffu */ - @CheckReturnValue(explanation = "should use the returned Cffu; otherwise, prefer method `thenAcceptBothFastFail`") - public Cffu thenCombineFastFail( - CompletionStage other, BiFunction fn) { - return reset0(CompletableFutureUtils.thenCombineFastFail(this, other, fn)); + public Cffu runAfterBothFastFail(CompletionStage other, Runnable action) { + return reset0(CompletableFutureUtils.runAfterBothFastFail(this, other, action)); } /** * Returns a new Cffu that, when this and the other given stage both complete normally, - * is executed using {@link #defaultExecutor()}, with the two results as arguments to the supplied function. + * executes the given action using {@link #defaultExecutor()}. * if any of the given stage complete exceptionally, then the returned Cffu also does so * *without* waiting other incomplete given CompletionStage, * with a CompletionException holding this exception as its cause. *

- * This method is the same as {@link #thenCombineAsync(CompletionStage, BiFunction)} + * This method is the same as {@link #runAfterBothAsync(CompletionStage, Runnable)} * except for the fast-fail behavior. * - * @param other the other CompletionStage - * @param fn the function to use to compute the value of the returned Cffu - * @param the type of the other CompletionStage's result - * @param the function's return type + * @param other the other CompletionStage + * @param action the action to perform before completing the returned Cffu * @return the new Cffu */ - @CheckReturnValue(explanation = "should use the returned Cffu; otherwise, prefer method `thenAcceptBothFastFailAsync`") - public Cffu thenCombineFastFailAsync( - CompletionStage other, BiFunction fn) { - return thenCombineFastFailAsync(other, fn, fac.defaultExecutor()); + public Cffu runAfterBothFastFailAsync(CompletionStage other, Runnable action) { + return runAfterBothFastFailAsync(other, action, fac.defaultExecutor()); } /** * Returns a new Cffu that, when this and the other given stage both complete normally, - * is executed using the supplied executor, with the two results as arguments to the supplied function. + * executes the given action using the supplied executor. * if any of the given stage complete exceptionally, then the returned Cffu also does so * *without* waiting other incomplete given CompletionStage, * with a CompletionException holding this exception as its cause. *

- * This method is the same as {@link #thenCombineAsync(CompletionStage, BiFunction, Executor)} + * This method is the same as {@link #runAfterBothAsync(CompletionStage, Runnable, Executor)} * except for the fast-fail behavior. * * @param other the other CompletionStage - * @param fn the function to use to compute the value of the returned Cffu + * @param action the action to perform before completing the returned Cffu * @param executor the executor to use for asynchronous execution - * @param the type of the other CompletionStage's result - * @param the function's return type * @return the new Cffu */ - @CheckReturnValue(explanation = "should use the returned Cffu; otherwise, prefer method `thenAcceptBothFastFailAsync`") - public Cffu thenCombineFastFailAsync(CompletionStage other, - BiFunction fn, - Executor executor) { - return reset0(CompletableFutureUtils.thenCombineFastFailAsync(this, other, fn, executor)); + public Cffu runAfterBothFastFailAsync(CompletionStage other, Runnable action, Executor executor) { + return reset0(CompletableFutureUtils.runAfterBothFastFailAsync(this, other, action, executor)); } + // endregion //////////////////////////////////////////////////////////////////////////////// - //# `then either(binary input)` methods of CompletionStage: + // region# thenEither* Methods(binary input) of CompletionStage // - // - runAfterEither*(Runnable): Void, Void -> Void - // - acceptEither*(Consumer): (T, T) -> Void // - applyToEither*(Function): (T, T) -> U + // - acceptEither*(Consumer): (T, T) -> Void + // - runAfterEither*(Runnable): Void, Void -> Void //////////////////////////////////////////////////////////////////////////////// /** * Returns a new Cffu that, when either this or the other given stage complete normally, - * executes the given action. + * is executed with the corresponding result as argument to the supplied function. *

* See the {@link CompletionStage} documentation for rules covering exceptional completion. * - * @param other the other CompletionStage - * @param action the action to perform before completing the returned Cffu + * @param other the other CompletionStage + * @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 `acceptEither`") @Override - public Cffu runAfterEither(CompletionStage other, Runnable action) { - return reset0(cf.runAfterEither(other, action)); + public Cffu applyToEither( + CompletionStage other, Function fn) { + return reset0(cf.applyToEither(other, fn)); } /** * Returns a new Cffu that, when either this or the other given stage complete normally, - * executes the given action using {@link #defaultExecutor()}. + * is executed using {@link #defaultExecutor()}, + * with the corresponding result as argument to the supplied function. *

* See the {@link CompletionStage} documentation for rules covering exceptional completion. * - * @param other the other CompletionStage - * @param action the action to perform before completing the returned Cffu + * @param other the other CompletionStage + * @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 `acceptEitherAsync`") @Override - public Cffu runAfterEitherAsync(CompletionStage other, Runnable action) { - return runAfterEitherAsync(other, action, fac.defaultExecutor()); + public Cffu applyToEitherAsync( + CompletionStage other, Function fn) { + return applyToEitherAsync(other, fn, fac.defaultExecutor()); } /** * Returns a new Cffu that, when either this or the other given stage complete normally, - * executes the given action using the supplied executor. + * is executed using the supplied executor, with the corresponding result as argument to the supplied function. *

* See the {@link CompletionStage} documentation for rules covering exceptional completion. * * @param other the other CompletionStage - * @param action the action to perform before completing 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 `acceptEitherAsync`") @Override - public Cffu runAfterEitherAsync( - CompletionStage other, Runnable action, Executor executor) { - return reset0(cf.runAfterEitherAsync(other, action, executor)); + public Cffu applyToEitherAsync(CompletionStage other, + Function fn, + Executor executor) { + return reset0(cf.applyToEitherAsync(other, fn, executor)); } /** - * Returns a new Cffu that, when either this or the other given stage complete normally, executes the given action. - * Otherwise, all two complete exceptionally, the returned Cffu also does so, - * with a CompletionException holding an exception from any of as its cause. + * Returns a new Cffu that, when either this or the other given stage complete normally, + * is executed with the corresponding result as argument to the supplied function. *

- * This method is the same as {@link #runAfterEither(CompletionStage, Runnable)} + * This method is the same as {@link #applyToEither(CompletionStage, Function)} * except for the either-success behavior instead of either-complete. * - * @param other the other CompletionStage - * @param action the action to perform before completing the returned Cffu + * @param other the other CompletionStage + * @param fn the function to use to compute the value of the returned Cffu + * @param the function's return type * @return the new Cffu */ - public Cffu runAfterEitherSuccess(CompletionStage other, Runnable action) { - return reset0(CompletableFutureUtils.runAfterEitherSuccess(this, other, action)); + @CheckReturnValue(explanation = "should use the returned Cffu; otherwise, prefer method `acceptEitherSuccess`") + public Cffu applyToEitherSuccess( + CompletionStage other, Function fn) { + return reset0(CompletableFutureUtils.applyToEitherSuccess(this, other, fn)); } /** * Returns a new Cffu that, when either this or the other given stage complete normally, - * executes the given action using {@link #defaultExecutor()}. - * Otherwise, all two complete exceptionally, the returned Cffu also does so, - * with a CompletionException holding an exception from any of as its cause. + * is executed using {@link #defaultExecutor()}, + * with the corresponding result as argument to the supplied function. *

- * This method is the same as {@link #runAfterEitherAsync(CompletionStage, Runnable)} + * This method is the same as {@link #applyToEitherAsync(CompletionStage, Function)} * except for the either-success behavior instead of either-complete. * - * @param other the other CompletionStage - * @param action the action to perform before completing the returned Cffu + * @param other the other CompletionStage + * @param fn the function to use to compute the value of the returned Cffu + * @param the function's return type * @return the new Cffu */ - public Cffu runAfterEitherSuccessAsync(CompletionStage other, Runnable action) { - return runAfterEitherSuccessAsync(other, action, fac.defaultExecutor()); + @CheckReturnValue(explanation = "should use the returned Cffu; otherwise, prefer method `acceptEitherSuccessAsync`") + public Cffu applyToEitherSuccessAsync( + CompletionStage other, Function fn) { + return applyToEitherSuccessAsync(other, fn, fac.defaultExecutor()); } /** * Returns a new Cffu that, when either this or the other given stage complete normally, - * executes the given action using the supplied executor. - * Otherwise, all two complete exceptionally, the returned Cffu also does so, - * with a CompletionException holding an exception from any of as its cause. + * is executed using the supplied executor, with the corresponding result as argument to the supplied function. *

- * This method is the same as {@link #runAfterEitherAsync(CompletionStage, Runnable, Executor)} + * This method is the same as {@link #applyToEitherAsync(CompletionStage, Function, Executor)} * except for the either-success behavior instead of either-complete. * * @param other the other CompletionStage - * @param action the action to perform before completing 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 */ - public Cffu runAfterEitherSuccessAsync( - CompletionStage other, Runnable action, Executor executor) { - return reset0(CompletableFutureUtils.runAfterEitherSuccessAsync(this, other, action, executor)); + @CheckReturnValue(explanation = "should use the returned Cffu; otherwise, prefer method `acceptEitherSuccessAsync`") + public Cffu applyToEitherSuccessAsync(CompletionStage other, + Function fn, + Executor executor) { + return reset0(CompletableFutureUtils.applyToEitherSuccessAsync(this, other, fn, executor)); } /** @@ -765,122 +787,109 @@ public Cffu acceptEitherSuccessAsync(CompletionStage other, return reset0(CompletableFutureUtils.acceptEitherSuccessAsync(this, other, action, executor)); } + /** * Returns a new Cffu that, when either this or the other given stage complete normally, - * is executed with the corresponding result as argument to the supplied function. + * executes the given action. *

* See the {@link CompletionStage} documentation for rules covering exceptional completion. * - * @param other the other CompletionStage - * @param fn the function to use to compute the value of the returned Cffu - * @param the function's return type + * @param other the other CompletionStage + * @param action the action to perform before completing the returned Cffu * @return the new Cffu */ - @CheckReturnValue(explanation = "should use the returned Cffu; otherwise, prefer method `acceptEither`") @Override - public Cffu applyToEither( - CompletionStage other, Function fn) { - return reset0(cf.applyToEither(other, fn)); + public Cffu runAfterEither(CompletionStage other, Runnable action) { + return reset0(cf.runAfterEither(other, action)); } /** * Returns a new Cffu that, when either this or the other given stage complete normally, - * is executed using {@link #defaultExecutor()}, - * with the corresponding result as argument to the supplied function. + * executes the given action using {@link #defaultExecutor()}. *

* See the {@link CompletionStage} documentation for rules covering exceptional completion. * - * @param other the other CompletionStage - * @param fn the function to use to compute the value of the returned Cffu - * @param the function's return type + * @param other the other CompletionStage + * @param action the action to perform before completing the returned Cffu * @return the new Cffu */ - @CheckReturnValue(explanation = "should use the returned Cffu; otherwise, prefer method `acceptEitherAsync`") @Override - public Cffu applyToEitherAsync( - CompletionStage other, Function fn) { - return applyToEitherAsync(other, fn, fac.defaultExecutor()); + public Cffu runAfterEitherAsync(CompletionStage other, Runnable action) { + return runAfterEitherAsync(other, action, fac.defaultExecutor()); } /** * Returns a new Cffu that, when either this or the other given stage complete normally, - * is executed using the supplied executor, with the corresponding result as argument to the supplied function. + * executes the given action using the supplied executor. *

* See the {@link CompletionStage} documentation for rules covering exceptional completion. * * @param other the other CompletionStage - * @param fn the function to use to compute the value of the returned Cffu + * @param action the action to perform before completing 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 `acceptEitherAsync`") @Override - public Cffu applyToEitherAsync(CompletionStage other, - Function fn, - Executor executor) { - return reset0(cf.applyToEitherAsync(other, fn, executor)); + public Cffu runAfterEitherAsync( + CompletionStage other, Runnable action, Executor executor) { + return reset0(cf.runAfterEitherAsync(other, action, executor)); } /** - * Returns a new Cffu that, when either this or the other given stage complete normally, - * is executed with the corresponding result as argument to the supplied function. + * Returns a new Cffu that, when either this or the other given stage complete normally, executes the given action. + * Otherwise, all two complete exceptionally, the returned Cffu also does so, + * with a CompletionException holding an exception from any of as its cause. *

- * This method is the same as {@link #applyToEither(CompletionStage, Function)} + * This method is the same as {@link #runAfterEither(CompletionStage, Runnable)} * except for the either-success behavior instead of either-complete. * - * @param other the other CompletionStage - * @param fn the function to use to compute the value of the returned Cffu - * @param the function's return type + * @param other the other CompletionStage + * @param action the action to perform before completing the returned Cffu * @return the new Cffu */ - @CheckReturnValue(explanation = "should use the returned Cffu; otherwise, prefer method `acceptEitherSuccess`") - public Cffu applyToEitherSuccess( - CompletionStage other, Function fn) { - return reset0(CompletableFutureUtils.applyToEitherSuccess(this, other, fn)); + public Cffu runAfterEitherSuccess(CompletionStage other, Runnable action) { + return reset0(CompletableFutureUtils.runAfterEitherSuccess(this, other, action)); } /** * Returns a new Cffu that, when either this or the other given stage complete normally, - * is executed using {@link #defaultExecutor()}, - * with the corresponding result as argument to the supplied function. + * executes the given action using {@link #defaultExecutor()}. + * Otherwise, all two complete exceptionally, the returned Cffu also does so, + * with a CompletionException holding an exception from any of as its cause. *

- * This method is the same as {@link #applyToEitherAsync(CompletionStage, Function)} + * This method is the same as {@link #runAfterEitherAsync(CompletionStage, Runnable)} * except for the either-success behavior instead of either-complete. * - * @param other the other CompletionStage - * @param fn the function to use to compute the value of the returned Cffu - * @param the function's return type + * @param other the other CompletionStage + * @param action the action to perform before completing the returned Cffu * @return the new Cffu */ - @CheckReturnValue(explanation = "should use the returned Cffu; otherwise, prefer method `acceptEitherSuccessAsync`") - public Cffu applyToEitherSuccessAsync( - CompletionStage other, Function fn) { - return applyToEitherSuccessAsync(other, fn, fac.defaultExecutor()); + public Cffu runAfterEitherSuccessAsync(CompletionStage other, Runnable action) { + return runAfterEitherSuccessAsync(other, action, fac.defaultExecutor()); } /** * Returns a new Cffu that, when either this or the other given stage complete normally, - * is executed using the supplied executor, with the corresponding result as argument to the supplied function. + * executes the given action using the supplied executor. + * Otherwise, all two complete exceptionally, the returned Cffu also does so, + * with a CompletionException holding an exception from any of as its cause. *

- * This method is the same as {@link #applyToEitherAsync(CompletionStage, Function, Executor)} + * This method is the same as {@link #runAfterEitherAsync(CompletionStage, Runnable, Executor)} * except for the either-success behavior instead of either-complete. * * @param other the other CompletionStage - * @param fn the function to use to compute the value of the returned Cffu + * @param action the action to perform before completing 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 `acceptEitherSuccessAsync`") - public Cffu applyToEitherSuccessAsync(CompletionStage other, - Function fn, - Executor executor) { - return reset0(CompletableFutureUtils.applyToEitherSuccessAsync(this, other, fn, executor)); + public Cffu runAfterEitherSuccessAsync( + CompletionStage other, Runnable action, Executor executor) { + return reset0(CompletableFutureUtils.runAfterEitherSuccessAsync(this, other, action, executor)); } + // endregion //////////////////////////////////////////////////////////////////////////////// - //# Error Handling methods of CompletionStage: + // region# Error Handling Methods of CompletionStage // // - exceptionally*: throwable -> T //////////////////////////////////////////////////////////////////////////////// @@ -932,8 +941,9 @@ public Cffu exceptionallyAsync(Function fn, Executor return reset0(CompletableFutureUtils.exceptionallyAsync(cf, fn, executor)); } + // endregion //////////////////////////////////////////////////////////////////////////////// - //# Timeout Control methods: + // region# Timeout Control Methods // // - orTimeout: timeout event -> complete with the given value // - completeOnTimeout: timeout event -> complete with TimeoutException @@ -1057,8 +1067,9 @@ public Cffu unsafeCompleteOnTimeout(@Nullable T value, long timeout, TimeUnit return this; } + // endregion //////////////////////////////////////////////////////////////////////////////// - //# Advanced methods of CompletionStage: + // region# Advanced Methods(compose* and handle-like methods) // // - thenCompose*: T -> CompletionStage // - exceptionallyCompose*: throwable -> CompletionStage @@ -1069,7 +1080,7 @@ public Cffu unsafeCompleteOnTimeout(@Nullable T value, long timeout, TimeUnit // // NOTE about advanced meaning: // - `compose` methods, input function argument return CompletionStage - // - handle successful and failed result together(handle*/whenComplete*) + // - handle successful and failed result together(handle*/whenComplete*/peek*) //////////////////////////////////////////////////////////////////////////////// /** @@ -1382,8 +1393,9 @@ public Cffu peekAsync(BiConsumer action, Execut return this; } + // endregion //////////////////////////////////////////////////////////////////////////////// - //# Read(explicitly) methods of CompletableFuture + // region# Read(explicitly) Methods // // - get() // BLOCKING! // - get(timeout, unit) // BLOCKING! @@ -1693,8 +1705,9 @@ public CffuState cffuState() { return CompletableFutureUtils.state(cf); } + // endregion //////////////////////////////////////////////////////////////////////////////// - //# Write methods of CompletableFuture + // region# Write Methods // // - complete(value): boolean // - completeAsync*: -> Cffu @@ -1790,8 +1803,9 @@ public boolean cancel(boolean mayInterruptIfRunning) { return cf.cancel(mayInterruptIfRunning); } + // endregion //////////////////////////////////////////////////////////////////////////////// - //# Cffu Re-Config methods + // region# Re-Config Methods // // - minimalCompletionStage() // - resetCffuFactory(cffuFactory) @@ -1882,8 +1896,9 @@ public Cffu copy() { return reset0(CompletableFutureUtils.copy(cf)); } + // endregion //////////////////////////////////////////////////////////////////////////////// - //# Getter methods of Cffu properties + // region# Getter Methods of Cffu properties // // - defaultExecutor() // - forbidObtrudeMethods() @@ -1948,8 +1963,9 @@ public boolean isMinimalStage() { return isMinimalStage; } + // endregion //////////////////////////////////////////////////////////////////////////////// - //# Inspection methods of Cffu + // region# Inspection Methods // // - cffuUnwrap() // - getNumberOfDependents() @@ -1985,14 +2001,14 @@ public int getNumberOfDependents() { return cf.getNumberOfDependents(); } + // endregion //////////////////////////////////////////////////////////////////////////////// - //# Other dangerous methods of CompletableFuture + // region# Other Uncommon Methods(dangerous or trivial) // + // - dangerous // - obtrudeValue(value) // - obtrudeException(ex) - // - //# methods of CompletableFuture for API compatibility - // + // - for API compatibility of CompletableFuture // - newIncompleteFuture() //////////////////////////////////////////////////////////////////////////////// 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 b2e96b31..ac418984 100644 --- a/cffu-core/src/main/java/io/foldright/cffu/CffuFactory.java +++ b/cffu-core/src/main/java/io/foldright/cffu/CffuFactory.java @@ -41,6 +41,10 @@ */ @ThreadSafe public final class CffuFactory { + //////////////////////////////////////////////////////////////////////////////// + // region# Builder and Constructor Methods(including internal constructors and fields) + //////////////////////////////////////////////////////////////////////////////// + private final Executor defaultExecutor; private final boolean forbidObtrudeMethods; @@ -71,110 +75,35 @@ private CompletionStage createMin(CompletableFuture cf) { return new Cffu<>(this, true, cf); } - //////////////////////////////////////////////////////////////////////////////// - //# Factory Methods, equivalent to same name static methods of CompletableFuture - // - // Create by immediate value - // - completedFuture/completedStage - // - failedFuture/failedStage - //////////////////////////////////////////////////////////////////////////////// - - /** - * Returns a new Cffu that is already completed with the given value. - * - * @param value the value - * @param the type of the value - * @return the completed Cffu - * @see CompletableFuture#completedFuture(Object) - */ - @Contract(pure = true) - public Cffu completedFuture(@Nullable T value) { - return create(CompletableFuture.completedFuture(value)); - } - /** - * Returns a new CompletionStage that is already completed with the given value - * and supports only those methods in interface {@link CompletionStage}. + * Return an incomplete Cffu, equivalent to {@link CompletableFuture#CompletableFuture()} constructor. *

- * CAUTION:
- * if run on old Java 8, just return a Cffu with - * a *normal* underlying CompletableFuture which is NOT with a *minimal* CompletionStage. - * - * @param value the value - * @param the type of the value - * @return the completed CompletionStage - * @see CompletableFuture#completedStage(Object) - * @see CompletableFuture#minimalCompletionStage() - */ - @Contract(pure = true) - public CompletionStage completedStage(@Nullable T value) { - return createMin((CompletableFuture) CompletableFutureUtils.completedStage(value)); - } - - /** - * Returns a new Cffu that is already completed exceptionally with the given exception. + * In general, should not use this method in biz code, prefer below factory methods of Cffu: * - * @param ex the exception - * @param the type of the value - * @return the exceptionally completed Cffu - * @see CompletableFuture#failedFuture(Throwable) - */ - @Contract(pure = true) - public Cffu failedFuture(Throwable ex) { - return create(CompletableFutureUtils.failedFuture(ex)); - } - - /** - * Returns a new CompletionStage that is already completed exceptionally - * with the given exception and supports only those methods in interface {@link CompletionStage}. - *

- * CAUTION:
- * if run on old Java 8, just return a Cffu with - * a *normal* underlying CompletableFuture which is NOT with a *minimal* CompletionStage. + *

    + *
  • {@link #runAsync(Runnable)} + *
  • {@link #supplyAsync(Supplier, Executor)} + *
* - * @param ex the exception - * @param the type of the value - * @return the exceptionally completed CompletionStage - * @see CompletableFuture#failedStage(Throwable) - * @see CompletableFuture#minimalCompletionStage() + * @see #supplyAsync(Supplier) + * @see #supplyAsync(Supplier, Executor) + * @see #runAsync(Runnable) + * @see #runAsync(Runnable, Executor) + * @see CompletableFuture#CompletableFuture() */ @Contract(pure = true) - public CompletionStage failedStage(Throwable ex) { - return createMin((CompletableFuture) CompletableFutureUtils.failedStage(ex)); + public Cffu newIncompleteCffu() { + return create(new CompletableFuture<>()); } + // endregion //////////////////////////////////////////////////////////////////////////////// - //# Factory Methods, equivalent to same name static methods of CompletableFuture - // - // create by logic/lambda - // - runAsync* - // - supplyAsync* + // region# Factory Methods //////////////////////////////////////////////////////////////////////////////// - /** - * Returns a new Cffu that is asynchronously completed by a task running - * in the {@link #defaultExecutor()} after it runs the given action. - * - * @param action the action to run before completing the returned Cffu - * @return the new Cffu - * @see CompletableFuture#runAsync(Runnable) - */ - public Cffu runAsync(Runnable action) { - return runAsync(action, defaultExecutor); - } - - /** - * Returns a new Cffu that is asynchronously completed - * by a task running in the given executor after it runs the given action. - * - * @param action the action to run before completing the returned Cffu - * @param executor the executor to use for asynchronous execution - * @return the new Cffu - * @see CompletableFuture#runAsync(Runnable, Executor) - */ - public Cffu runAsync(Runnable action, Executor executor) { - return create(CompletableFuture.runAsync(action, executor)); - } + //////////////////////////////////////////////////////////////////////////////// + // region## supplyAsync*/runAsync* Methods(create by action) + //////////////////////////////////////////////////////////////////////////////// /** * Returns a new Cffu that is asynchronously completed @@ -206,82 +135,108 @@ public Cffu supplyAsync(Supplier supplier, Executor executor) { return create(CompletableFuture.supplyAsync(supplier, executor)); } + /** + * Returns a new Cffu that is asynchronously completed by a task running + * in the {@link #defaultExecutor()} after it runs the given action. + * + * @param action the action to run before completing the returned Cffu + * @return the new Cffu + * @see CompletableFuture#runAsync(Runnable) + */ + public Cffu runAsync(Runnable action) { + return runAsync(action, defaultExecutor); + } + + /** + * Returns a new Cffu that is asynchronously completed + * by a task running in the given executor after it runs the given action. + * + * @param action the action to run before completing the returned Cffu + * @param executor the executor to use for asynchronous execution + * @return the new Cffu + * @see CompletableFuture#runAsync(Runnable, Executor) + */ + public Cffu runAsync(Runnable action, Executor executor) { + return create(CompletableFuture.runAsync(action, executor)); + } + + // endregion //////////////////////////////////////////////////////////////////////////////// - //# Factory Methods - // - // - newIncompleteCffu: equivalent to CompletableFuture constructor + // region## allOf* Methods(including mostResultsOfSuccess) // - // - toCffu: CF/CompletionStage -> Cffu - // - toCffuArray: CF/CompletionStage[] -> Cffu[] + // - allResultsOfFastFail + // - mostResultsOfSuccess + // - allResultsOf + // - allOf / allOfFastFail //////////////////////////////////////////////////////////////////////////////// /** - * Return an incomplete Cffu, equivalent to {@link CompletableFuture#CompletableFuture()} constructor. + * Returns a new Cffu that is successful with the results in the same order + * of the given stages arguments when all the given stages success; + * If any of the given stages complete exceptionally, then the returned Cffu also does so + * *without* waiting other incomplete given stages, with a CompletionException holding this exception as its cause. + * If no stages are provided, returns a Cffu completed with the value empty list. *

- * In general, should not use this method in biz code, prefer below factory methods of Cffu: - * - *

    - *
  • {@link #runAsync(Runnable)} - *
  • {@link #supplyAsync(Supplier, Executor)} - *
+ * This method is the same as {@link #allResultsOf(CompletionStage[])} except for the fast-fail behavior. + *

+ * This method is the same as {@link #allOfFastFail(CompletionStage[])}, + * except that the returned Cffu contains the results of the given stages. * - * @see #runAsync(Runnable) - * @see #runAsync(Runnable, Executor) - * @see #supplyAsync(Supplier) - * @see #supplyAsync(Supplier, Executor) - * @see CompletableFuture#CompletableFuture() + * @param cfs the stages + * @return a new Cffu that is successful when all the given stages success + * @throws NullPointerException if the array or any of its elements are {@code null} + * @see #allResultsOf(CompletionStage[]) + * @see #allOfFastFail(CompletionStage[]) + * @see #allOf(CompletionStage[]) */ @Contract(pure = true) - public Cffu newIncompleteCffu() { - return create(new CompletableFuture<>()); + @SafeVarargs + public final Cffu> allResultsOfFastFail(CompletionStage... cfs) { + return create(CompletableFutureUtils.allResultsOfFastFail(cfs)); } /** - * Returns a Cffu maintaining the same completion properties as this stage and this {@code CffuFactory} config. - * If this stage is already a Cffu and have the same {@code CffuFactory}, this method may return this stage itself. + * Returns a new Cffu with the most results in the same order of + * the given stages arguments in the given time({@code timeout}, aka as many results as possible in the given time). + *

+ * If the given stage is successful, its result is the completed value; Otherwise the given valueIfNotSuccess. * - * @throws NullPointerException if the given stage is null - * @see #toCffuArray(CompletionStage[]) - * @see CompletionStage#toCompletableFuture() - * @see Cffu#resetCffuFactory(CffuFactory) + * @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 cfs the stages + * @see Cffu#getSuccessNow(Object) */ @Contract(pure = true) - public Cffu toCffu(CompletionStage stage) { - requireNonNull(stage, "stage is null"); - if (stage instanceof Cffu) { - Cffu f = ((Cffu) stage); - if (f.cffuFactory() == this && !f.isMinimalStage()) return f; - } - return create(stage.toCompletableFuture()); + @SafeVarargs + public final Cffu> mostResultsOfSuccess( + @Nullable T valueIfNotSuccess, long timeout, TimeUnit unit, CompletionStage... cfs) { + return create(CompletableFutureUtils.mostResultsOfSuccess( + valueIfNotSuccess, defaultExecutor, timeout, unit, cfs)); } /** - * A convenient util method for wrap input {@link CompletableFuture} / {@link CompletionStage} / {@link Cffu} - * array element by {@link #toCffu(CompletionStage)}. + * Returns a new Cffu with the results in the same order of the given stages arguments, + * the new Cffu is completed when all the given stages complete; + * If any of the given stages complete exceptionally, then the returned Cffu also does so, + * with a CompletionException holding this exception as its cause. + * If no stages are provided, returns a Cffu completed with the value empty list. + *

+ * This method is the same as {@link #allOf(CompletionStage[])}, + * except that the returned Cffu contains the results of the given stages. * + * @param cfs the stages + * @return a new Cffu that is completed when all the given stages complete * @throws NullPointerException if the array or any of its elements are {@code null} - * @see #toCffu(CompletionStage) + * @see #allResultsOfFastFail(CompletionStage[]) + * @see #allOf(CompletionStage[]) */ @Contract(pure = true) @SafeVarargs - public final Cffu[] toCffuArray(CompletionStage... stages) { - requireNonNull(stages, "stages is null"); - @SuppressWarnings("unchecked") - Cffu[] ret = new Cffu[stages.length]; - for (int i = 0; i < stages.length; i++) { - ret[i] = toCffu(requireNonNull(stages[i], "stage" + (i + 1) + " is null")); - } - return ret; + public final Cffu> allResultsOf(CompletionStage... cfs) { + return create(CompletableFutureUtils.allResultsOf(cfs)); } - //////////////////////////////////////////////////////////////////////////////// - //# allOf*/mostResultsOfSuccess methods - // - // - allOf / allOfFastFail - // - allResultsOf / allResultsOfFastFail - // - mostResultsOfSuccess - //////////////////////////////////////////////////////////////////////////////// - /** * Returns a new Cffu that is completed when all the given stages complete; * If any of the given stages complete exceptionally, then the returned Cffu also does so, @@ -324,28 +279,6 @@ public Cffu allOf(CompletionStage... cfs) { return create(CompletableFutureUtils.allOf(cfs)); } - /** - * Returns a new Cffu with the results in the same order of the given stages arguments, - * the new Cffu is completed when all the given stages complete; - * If any of the given stages complete exceptionally, then the returned Cffu also does so, - * with a CompletionException holding this exception as its cause. - * If no stages are provided, returns a Cffu completed with the value empty list. - *

- * This method is the same as {@link #allOf(CompletionStage[])}, - * except that the returned Cffu contains the results of the given stages. - * - * @param cfs the stages - * @return a new Cffu that is completed when all the given stages complete - * @throws NullPointerException if the array or any of its elements are {@code null} - * @see #allResultsOfFastFail(CompletionStage[]) - * @see #allOf(CompletionStage[]) - */ - @Contract(pure = true) - @SafeVarargs - public final Cffu> allResultsOf(CompletionStage... cfs) { - return create(CompletableFutureUtils.allResultsOf(cfs)); - } - /** * Returns a new Cffu that is successful when all the given stages success; * If any of the given stages complete exceptionally, then the returned Cffu also does so @@ -387,58 +320,32 @@ public Cffu allOfFastFail(CompletionStage... cfs) { return create(CompletableFutureUtils.allOfFastFail(cfs)); } + // endregion + //////////////////////////////////////////////////////////////////////////////// + // region## anyOf* Methods + //////////////////////////////////////////////////////////////////////////////// + /** - * Returns a new Cffu that is successful with the results in the same order - * of the given stages arguments when all the given stages success; - * If any of the given stages complete exceptionally, then the returned Cffu also does so - * *without* waiting other incomplete given stages, with a CompletionException holding this exception as its cause. - * If no stages are provided, returns a Cffu completed with the value empty list. - *

- * This method is the same as {@link #allResultsOf(CompletionStage[])} except for the fast-fail behavior. + * Returns a new Cffu that is successful when any of the given stages success, + * with the same result. Otherwise, all the given stages complete exceptionally, + * the returned Cffu also does so, with a CompletionException holding + * an exception from any of the given stages as its cause. If no stages are provided, + * returns a new Cffu that is already completed exceptionally + * with a CompletionException holding a {@link NoCfsProvidedException} as its cause. *

- * This method is the same as {@link #allOfFastFail(CompletionStage[])}, - * except that the returned Cffu contains the results of the given stages. + * This method is the same as {@link #anyOf(CompletionStage[])} + * except for the any-success behavior instead of any-complete. * * @param cfs the stages - * @return a new Cffu that is successful when all the given stages success + * @return a new Cffu that is successful when any of the given stages success, with the same result * @throws NullPointerException if the array or any of its elements are {@code null} - * @see #allResultsOf(CompletionStage[]) - * @see #allOfFastFail(CompletionStage[]) - * @see #allOf(CompletionStage[]) - */ - @Contract(pure = true) - @SafeVarargs - public final Cffu> allResultsOfFastFail(CompletionStage... cfs) { - return create(CompletableFutureUtils.allResultsOfFastFail(cfs)); - } - - /** - * Returns a new Cffu with the most results in the same order of - * the given stages arguments in the given time({@code timeout}, aka as many results as possible in the given time). - *

- * If the given stage is successful, its 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 cfs the stages - * @see Cffu#getSuccessNow(Object) + * @see #anyOf(CompletionStage[]) */ - @Contract(pure = true) @SafeVarargs - public final Cffu> mostResultsOfSuccess( - @Nullable T valueIfNotSuccess, long timeout, TimeUnit unit, CompletionStage... cfs) { - return create(CompletableFutureUtils.mostResultsOfSuccess( - valueIfNotSuccess, defaultExecutor, timeout, unit, cfs)); + public final Cffu anyOfSuccess(CompletionStage... cfs) { + return create(CompletableFutureUtils.anyOfSuccess(cfs)); } - //////////////////////////////////////////////////////////////////////////////// - //# anyOf* methods: - // - // - anyOf - // - anyOfSuccess - //////////////////////////////////////////////////////////////////////////////// - /** * Returns a new Cffu that is completed when any of the given stages complete, with the same result.
* Otherwise, if it completed exceptionally, the returned Cffu also does so, @@ -462,50 +369,11 @@ public final Cffu anyOf(CompletionStage... cfs) { return create(CompletableFutureUtils.anyOf(cfs)); } - /** - * Returns a new Cffu that is successful when any of the given stages success, - * with the same result. Otherwise, all the given stages complete exceptionally, - * the returned Cffu also does so, with a CompletionException holding - * an exception from any of the given stages as its cause. If no stages are provided, - * returns a new Cffu that is already completed exceptionally - * with a CompletionException holding a {@link NoCfsProvidedException} as its cause. - *

- * This method is the same as {@link #anyOf(CompletionStage[])} - * except for the any-success behavior instead of any-complete. - * - * @param cfs the stages - * @return a new Cffu that is successful when any of the given stages success, with the same result - * @throws NullPointerException if the array or any of its elements are {@code null} - * @see #anyOf(CompletionStage[]) - */ - @SafeVarargs - public final Cffu anyOfSuccess(CompletionStage... cfs) { - return create(CompletableFutureUtils.anyOfSuccess(cfs)); - } - + // endregion //////////////////////////////////////////////////////////////////////////////// - //# New type-safe allTupleOf Factory Methods, support 2~5 input arguments - // - // - allTupleOf - // - allTupleOfFastFail - // - mostTupleOfSuccess + // region## allTupleOf*/mostTupleOfSuccess Methods //////////////////////////////////////////////////////////////////////////////// - /** - * Returns a new Cffu that is completed when the given two stages complete. - * If any of the given stages complete exceptionally, then the returned Cffu also does so, - * with a CompletionException holding this exception as its cause. - * - * @return a new Cffu that is completed when the given two stages complete - * @throws NullPointerException if any of the given stages are {@code null} - * @see #allResultsOf(CompletionStage[]) - */ - @Contract(pure = true) - public Cffu> allTupleOf( - CompletionStage cf1, CompletionStage cf2) { - return create(CompletableFutureUtils.allTupleOf(cf1, cf2)); - } - /** * Returns a new Cffu that is successful when the given two stages success. * If any of the given stages complete exceptionally, then the returned Cffu also does so @@ -525,18 +393,18 @@ public Cffu> allTupleOfFastFail( } /** - * Returns a new Cffu that is completed when the given three stages complete. + * Returns a new Cffu that is completed when the given two stages complete. * If any of the given stages complete exceptionally, then the returned Cffu also does so, * with a CompletionException holding this exception as its cause. * - * @return a new Cffu that is completed when the given three stages complete + * @return a new Cffu that is completed when the given two stages complete * @throws NullPointerException if any of the given stages are {@code null} * @see #allResultsOf(CompletionStage[]) */ @Contract(pure = true) - public Cffu> allTupleOf( - CompletionStage cf1, CompletionStage cf2, CompletionStage cf3) { - return create(CompletableFutureUtils.allTupleOf(cf1, cf2, cf3)); + public Cffu> allTupleOf( + CompletionStage cf1, CompletionStage cf2) { + return create(CompletableFutureUtils.allTupleOf(cf1, cf2)); } /** @@ -558,19 +426,18 @@ public Cffu> allTupleOfFastFail( } /** - * Returns a new Cffu that is completed when the given four stages complete. + * Returns a new Cffu that is completed when the given three stages complete. * If any of the given stages complete exceptionally, then the returned Cffu also does so, * with a CompletionException holding this exception as its cause. * - * @return a new Cffu that is completed when the given four stages complete + * @return a new Cffu that is completed when the given three stages complete * @throws NullPointerException if any of the given stages are {@code null} * @see #allResultsOf(CompletionStage[]) */ @Contract(pure = true) - public Cffu> allTupleOf( - CompletionStage cf1, CompletionStage cf2, - CompletionStage cf3, CompletionStage cf4) { - return create(CompletableFutureUtils.allTupleOf(cf1, cf2, cf3, cf4)); + public Cffu> allTupleOf( + CompletionStage cf1, CompletionStage cf2, CompletionStage cf3) { + return create(CompletableFutureUtils.allTupleOf(cf1, cf2, cf3)); } /** @@ -593,19 +460,19 @@ public Cffu> allTupleOfFastFail( } /** - * Returns a new Cffu that is completed when the given five stages complete. + * Returns a new Cffu that is completed when the given four stages complete. * If any of the given stages complete exceptionally, then the returned Cffu also does so, * with a CompletionException holding this exception as its cause. * - * @return a new Cffu that is completed when the given five stages complete + * @return a new Cffu that is completed when the given four stages complete * @throws NullPointerException if any of the given stages are {@code null} * @see #allResultsOf(CompletionStage[]) */ @Contract(pure = true) - public Cffu> allTupleOf( - CompletionStage cf1, CompletionStage cf2, CompletionStage cf3, - CompletionStage cf4, CompletionStage cf5) { - return create(CompletableFutureUtils.allTupleOf(cf1, cf2, cf3, cf4, cf5)); + public Cffu> allTupleOf( + CompletionStage cf1, CompletionStage cf2, + CompletionStage cf3, CompletionStage cf4) { + return create(CompletableFutureUtils.allTupleOf(cf1, cf2, cf3, cf4)); } /** @@ -627,6 +494,22 @@ public Cffu> allTupleOfFastFail( return create(CompletableFutureUtils.allTupleOfFastFail(cf1, cf2, cf3, cf4, cf5)); } + /** + * Returns a new Cffu that is completed when the given five stages complete. + * If any of the given stages complete exceptionally, then the returned Cffu also does so, + * with a CompletionException holding this exception as its cause. + * + * @return a new Cffu that is completed when the given five stages complete + * @throws NullPointerException if any of the given stages are {@code null} + * @see #allResultsOf(CompletionStage[]) + */ + @Contract(pure = true) + public Cffu> allTupleOf( + CompletionStage cf1, CompletionStage cf2, CompletionStage cf3, + CompletionStage cf4, CompletionStage cf5) { + return create(CompletableFutureUtils.allTupleOf(cf1, cf2, cf3, cf4, cf5)); + } + /** * Returns a new Cffu with the most results in the same order of * the given two stages arguments in the given time({@code timeout}, aka as many results as possible in the given time). @@ -704,10 +587,125 @@ public Cffu> mostTupleOfSuccess( return create(CompletableFutureUtils.mostTupleOfSuccess(defaultExecutor, timeout, unit, cf1, cf2, cf3, cf4, cf5)); } + // endregion + //////////////////////////////////////////////////////////////////////////////// + // region## Immediate Value Argument Factory Methods + //////////////////////////////////////////////////////////////////////////////// + + /** + * Returns a new Cffu that is already completed with the given value. + * + * @param value the value + * @param the type of the value + * @return the completed Cffu + * @see CompletableFuture#completedFuture(Object) + */ + @Contract(pure = true) + public Cffu completedFuture(@Nullable T value) { + return create(CompletableFuture.completedFuture(value)); + } + + /** + * Returns a new CompletionStage that is already completed with the given value + * and supports only those methods in interface {@link CompletionStage}. + *

+ * CAUTION:
+ * if run on old Java 8, just return a Cffu with + * a *normal* underlying CompletableFuture which is NOT with a *minimal* CompletionStage. + * + * @param value the value + * @param the type of the value + * @return the completed CompletionStage + * @see CompletableFuture#completedStage(Object) + * @see CompletableFuture#minimalCompletionStage() + */ + @Contract(pure = true) + public CompletionStage completedStage(@Nullable T value) { + return createMin((CompletableFuture) CompletableFutureUtils.completedStage(value)); + } + + /** + * Returns a new Cffu that is already completed exceptionally with the given exception. + * + * @param ex the exception + * @param the type of the value + * @return the exceptionally completed Cffu + * @see CompletableFuture#failedFuture(Throwable) + */ + @Contract(pure = true) + public Cffu failedFuture(Throwable ex) { + return create(CompletableFutureUtils.failedFuture(ex)); + } + + /** + * Returns a new CompletionStage that is already completed exceptionally + * with the given exception and supports only those methods in interface {@link CompletionStage}. + *

+ * CAUTION:
+ * if run on old Java 8, just return a Cffu with + * a *normal* underlying CompletableFuture which is NOT with a *minimal* CompletionStage. + * + * @param ex the exception + * @param the type of the value + * @return the exceptionally completed CompletionStage + * @see CompletableFuture#failedStage(Throwable) + * @see CompletableFuture#minimalCompletionStage() + */ + @Contract(pure = true) + public CompletionStage failedStage(Throwable ex) { + return createMin((CompletableFuture) CompletableFutureUtils.failedStage(ex)); + } + + // endregion //////////////////////////////////////////////////////////////////////////////// - //# Delay Execution, equivalent to same name static methods of CompletableFuture + // region## CompletionStage Argument Factory Methods // - // - delayedExecutor + // - toCffu: CF/CompletionStage -> Cffu + // - toCffuArray: CF/CompletionStage[] -> Cffu[] + //////////////////////////////////////////////////////////////////////////////// + + /** + * Returns a Cffu maintaining the same completion properties as this stage and this {@code CffuFactory} config. + * If this stage is already a Cffu and have the same {@code CffuFactory}, this method may return this stage itself. + * + * @throws NullPointerException if the given stage is null + * @see #toCffuArray(CompletionStage[]) + * @see CompletionStage#toCompletableFuture() + * @see Cffu#resetCffuFactory(CffuFactory) + */ + @Contract(pure = true) + public Cffu toCffu(CompletionStage stage) { + requireNonNull(stage, "stage is null"); + if (stage instanceof Cffu) { + Cffu f = ((Cffu) stage); + if (f.cffuFactory() == this && !f.isMinimalStage()) return f; + } + return create(stage.toCompletableFuture()); + } + + /** + * A convenient util method for wrap input {@link CompletableFuture} / {@link CompletionStage} / {@link Cffu} + * array element by {@link #toCffu(CompletionStage)}. + * + * @throws NullPointerException if the array or any of its elements are {@code null} + * @see #toCffu(CompletionStage) + */ + @Contract(pure = true) + @SafeVarargs + public final Cffu[] toCffuArray(CompletionStage... stages) { + requireNonNull(stages, "stages is null"); + @SuppressWarnings("unchecked") + Cffu[] ret = new Cffu[stages.length]; + for (int i = 0; i < stages.length; i++) { + ret[i] = toCffu(requireNonNull(stages[i], "stage" + (i + 1) + " is null")); + } + return ret; + } + + // endregion + // endregion + //////////////////////////////////////////////////////////////////////////////// + // region# Delay Execution //////////////////////////////////////////////////////////////////////////////// /** @@ -739,8 +737,9 @@ public Executor delayedExecutor(long delay, TimeUnit unit, Executor executor) { return CompletableFutureUtils.delayedExecutor(delay, unit, executor); } + // endregion //////////////////////////////////////////////////////////////////////////////// - //# Conversion (Static) Methods + // region# Conversion Methods(static methods) // // - cffuArrayUnwrap: Cffu[] -> CompletableFuture[] // - cffuListToArray: List -> Cffu[] @@ -750,6 +749,7 @@ public Executor delayedExecutor(long delay, TimeUnit unit, Executor executor) { * A convenient util method for unwrap input {@link Cffu} array elements by {@link Cffu#cffuUnwrap()}. * * @param cfs the Cffus + * @see CompletableFutureUtils#toCompletableFutureArray(CompletionStage[]) * @see Cffu#cffuUnwrap() */ @Contract(pure = true) @@ -765,6 +765,8 @@ public static CompletableFuture[] cffuArrayUnwrap(Cffu... cfs) { /** * Convert Cffu list to Cffu array. + * + * @see CompletableFutureUtils#completableFutureListToArray(List) */ @Contract(pure = true) public static Cffu[] cffuListToArray(List> cffuList) { @@ -773,8 +775,9 @@ public static Cffu[] cffuListToArray(List> cffuList) { return cffuList.toArray(a); } + // endregion //////////////////////////////////////////////////////////////////////////////// - //# Getter methods of CffuFactory properties + // region# Getter Methods of CffuFactory properties //////////////////////////////////////////////////////////////////////////////// /** 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 d2e62284..c597df0e 100644 --- a/cffu-core/src/main/java/io/foldright/cffu/CompletableFutureUtils.java +++ b/cffu-core/src/main/java/io/foldright/cffu/CompletableFutureUtils.java @@ -22,19 +22,176 @@ /** - * This class contains the enhanced and backport methods for {@link CompletableFuture}. + * This class contains the new enhanced and backport methods for {@link CompletableFuture}. * * @author Jerry Lee (oldratlee at gmail dot com) */ public final class CompletableFutureUtils { //////////////////////////////////////////////////////////////////////////////// - //# multi-actions(M*) methods + // region# CF Factory Methods(including static methods of CF) + //////////////////////////////////////////////////////////////////////////////// + + //////////////////////////////////////////////////////////// + // region## Multi-Actions(M*) Methods(create by actions) // - // - mRun*Async(Runnable): Runnable* -> CompletableFuture - // mRunAsync / mRunFastFailAsync // - mSupply*Async(Supplier): Supplier* -> CompletableFuture> // mSupplyAsync / mSupplyFastFailAsync / mSupplyMostSuccessAsync - //////////////////////////////////////////////////////////////////////////////// + // - mRun*Async(Runnable): Runnable* -> CompletableFuture + // mRunAsync / mRunFastFailAsync + //////////////////////////////////////////////////////////// + + /** + * 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) + */ + @SafeVarargs + public static CompletableFuture> mSupplyFastFailAsync(Supplier... suppliers) { + return mSupplyFastFailAsync(AsyncPoolHolder.ASYNC_POOL, suppliers); + } + + /** + * Returns a new CompletableFuture that is asynchronously completed + * by tasks running in the given Executor 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(Executor, Supplier[])} except for the fast-fail behavior. + * + * @param executor the executor to use for asynchronous execution + * @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, Executor) + */ + @SafeVarargs + public static CompletableFuture> mSupplyFastFailAsync( + Executor executor, Supplier... suppliers) { + requireNonNull(executor, "executor is null"); + requireArrayAndEleNonNull("supplier", suppliers); + + return allResultsOfFastFail(wrapSuppliers(executor, 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) + */ + @SafeVarargs + public static CompletableFuture> mSupplyMostSuccessAsync( + @Nullable T valueIfNotSuccess, long timeout, TimeUnit unit, Supplier... suppliers) { + return mSupplyMostSuccessAsync(valueIfNotSuccess, AsyncPoolHolder.ASYNC_POOL, timeout, unit, suppliers); + } + + /** + * Returns a new CompletableFuture that is asynchronously completed + * by tasks running in the given Executor 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 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 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, Executor, long, TimeUnit, CompletionStage[]) + * @see CompletableFuture#supplyAsync(Supplier, Executor) + */ + @SafeVarargs + public static CompletableFuture> mSupplyMostSuccessAsync( + @Nullable T valueIfNotSuccess, Executor executor, long timeout, TimeUnit unit, + Supplier... suppliers) { + requireNonNull(executor, "executor is null"); + requireNonNull(unit, "unit is null"); + requireArrayAndEleNonNull("supplier", suppliers); + + return mostResultsOfSuccess(valueIfNotSuccess, executor, timeout, unit, wrapSuppliers(executor, 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) + */ + @SafeVarargs + public static CompletableFuture> mSupplyAsync(Supplier... suppliers) { + return mSupplyAsync(AsyncPoolHolder.ASYNC_POOL, suppliers); + } + + /** + * Returns a new CompletableFuture that is asynchronously completed + * by tasks running in the given Executor with the values obtained by calling the given Suppliers + * in the same order of the given Suppliers arguments. + * + * @param executor the executor to use for asynchronous execution + * @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, Executor) + */ + @SafeVarargs + public static CompletableFuture> mSupplyAsync(Executor executor, Supplier... suppliers) { + requireNonNull(executor, "executor is null"); + requireArrayAndEleNonNull("supplier", suppliers); + + return allResultsOf(wrapSuppliers(executor, suppliers)); + } + + @SafeVarargs + private static T[] requireArrayAndEleNonNull(String varName, T... array) { + requireNonNull(array, varName + "s is null"); + for (int i = 0; i < array.length; i++) { + requireNonNull(array[i], varName + (i + 1) + " is null"); + } + return array; + } + + private static CompletableFuture[] wrapSuppliers( + Executor executor, Supplier[] suppliers) { + @SuppressWarnings("unchecked") + CompletableFuture[] cfs = new CompletableFuture[suppliers.length]; + for (int i = 0; i < suppliers.length; i++) { + cfs[i] = CompletableFuture.supplyAsync(suppliers[i], executor); + } + return cfs; + } /** * Returns a new CompletableFuture that is asynchronously completed @@ -102,15 +259,6 @@ public static CompletableFuture mRunFastFailAsync(Executor executor, Runna return allOfFastFail(wrapActions(executor, actions)); } - @SafeVarargs - private static T[] requireArrayAndEleNonNull(String varName, T... array) { - requireNonNull(array, varName + "s is null"); - for (int i = 0; i < array.length; i++) { - requireNonNull(array[i], varName + (i + 1) + " is null"); - } - return array; - } - private static CompletableFuture[] wrapActions(Executor executor, Runnable[] actions) { @SuppressWarnings("unchecked") CompletableFuture[] cfs = new CompletableFuture[actions.length]; @@ -120,154 +268,166 @@ private static CompletableFuture[] wrapActions(Executor executor, Runnable return cfs; } - /** - * 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) - */ - @SafeVarargs - public static CompletableFuture> mSupplyAsync(Supplier... suppliers) { - return mSupplyAsync(AsyncPoolHolder.ASYNC_POOL, suppliers); - } + // endregion + //////////////////////////////////////////////////////////// + // region## allOf* Methods(including mostResultsOfSuccess) + // + // - allResultsOfFastFail + // - mostResultsOfSuccess + // - allResultsOf + // - allOf / allOfFastFail + //////////////////////////////////////////////////////////// /** - * Returns a new CompletableFuture that is asynchronously completed - * by tasks running in the given Executor with the values obtained by calling the given Suppliers - * in the same order of the given Suppliers arguments. + * Returns a new CompletableFuture that is successful with the results in the same order + * of the given stages arguments when all the given stages success; + * If any of the given stages complete exceptionally, then the returned CompletableFuture also does so + * *without* waiting other incomplete given stages, with a CompletionException holding this exception as its cause. + * If no stages are provided, returns a CompletableFuture completed with the value empty list. + *

+ * This method is the same as {@link #allResultsOf(CompletionStage[])} except for the fast-fail behavior. + *

+ * This method is the same as {@link #allOfFastFail(CompletionStage[])}, + * except that the returned CompletableFuture contains the results of the given stages. * - * @param executor the executor to use for asynchronous execution - * @param suppliers the suppliers returning the value to be used to complete the returned CompletableFuture - * @param the suppliers' return type - * @return the new CompletableFuture + * @param cfs the stages + * @return a new CompletableFuture that is successful when all the given stages success + * @throws NullPointerException if the array or any of its elements are {@code null} * @see #allResultsOf(CompletionStage[]) - * @see CompletableFuture#supplyAsync(Supplier, Executor) + * @see #allOfFastFail(CompletionStage[]) + * @see #allOf(CompletionStage[]) */ + @Contract(pure = true) @SafeVarargs - public static CompletableFuture> mSupplyAsync(Executor executor, Supplier... suppliers) { - requireNonNull(executor, "executor is null"); - requireArrayAndEleNonNull("supplier", suppliers); + public static CompletableFuture> allResultsOfFastFail(CompletionStage... cfs) { + requireCfsAndEleNonNull(cfs); + final int len = cfs.length; + if (len == 0) return completedFuture(arrayList()); + // Defensive copy input cf to non-minimal-stage instance(toNonMinCfCopy) for SINGLE input + // in order to ensure that the returned cf is not minimal-stage CF instance(UnsupportedOperationException) + if (len == 1) return toNonMinCfCopy(cfs[0]).thenApply(CompletableFutureUtils::arrayList); - return allResultsOf(wrapSuppliers(executor, suppliers)); + final CompletableFuture[] successOrBeIncomplete = new CompletableFuture[len]; + // NOTE: fill ONE MORE element of failedOrBeIncomplete LATER + final CompletableFuture[] failedOrBeIncomplete = new CompletableFuture[len + 1]; + fill(cfs, successOrBeIncomplete, failedOrBeIncomplete); + + // NOTE: fill the ONE MORE element of failedOrBeIncomplete HERE: + // a cf that is successful when all given cfs success, otherwise be incomplete + failedOrBeIncomplete[len] = allResultsOf(successOrBeIncomplete); + + CompletableFuture ret = CompletableFuture.anyOf(failedOrBeIncomplete); + return f_cast(ret); } /** - * 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. + * Returns a new CompletableFuture with the most results in the same order of + * the given stages arguments in the given time({@code timeout}, aka as many results as possible in the given time). *

- * This method is the same as {@link #mSupplyAsync(Supplier[])} except for the fast-fail behavior. + * If the given stage is successful, its result is the completed value; Otherwise the given valueIfNotSuccess. * - * @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) + * @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 cfs the stages + * @see #getSuccessNow(CompletableFuture, Object) */ + @Contract(pure = true) @SafeVarargs - public static CompletableFuture> mSupplyFastFailAsync(Supplier... suppliers) { - return mSupplyFastFailAsync(AsyncPoolHolder.ASYNC_POOL, suppliers); + public static CompletableFuture> mostResultsOfSuccess( + @Nullable T valueIfNotSuccess, long timeout, TimeUnit unit, CompletionStage... cfs) { + return mostResultsOfSuccess(valueIfNotSuccess, AsyncPoolHolder.ASYNC_POOL, timeout, unit, cfs); } /** - * Returns a new CompletableFuture that is asynchronously completed - * by tasks running in the given Executor with the values obtained by calling the given Suppliers - * in the same order of the given Suppliers arguments. + * Returns a new CompletableFuture with the most results in the same order of + * the given stages arguments in the given time({@code timeout}, aka as many results as possible in the given time). *

- * This method is the same as {@link #mSupplyAsync(Executor, Supplier[])} except for the fast-fail behavior. + * If the given stage is successful, its result is the completed value; Otherwise the given valueIfNotSuccess. * - * @param executor the executor to use for asynchronous execution - * @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, Executor) + * @param valueIfNotSuccess the value to return if not completed successfully + * @param executorWhenTimeout the async executor when triggered by timeout + * @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 cfs the stages + * @see #getSuccessNow(CompletableFuture, Object) */ + @Contract(pure = true) @SafeVarargs - public static CompletableFuture> mSupplyFastFailAsync( - Executor executor, Supplier... suppliers) { - requireNonNull(executor, "executor is null"); - requireArrayAndEleNonNull("supplier", suppliers); + public static CompletableFuture> mostResultsOfSuccess( + @Nullable T valueIfNotSuccess, Executor executorWhenTimeout, long timeout, TimeUnit unit, + CompletionStage... cfs) { + requireNonNull(executorWhenTimeout, "executorWhenTimeout is null"); + requireNonNull(unit, "unit is null"); + requireNonNull(cfs, "cfs is null"); - return allResultsOfFastFail(wrapSuppliers(executor, suppliers)); + if (cfs.length == 0) return completedFuture(arrayList()); + if (cfs.length == 1) { + // Defensive copy input cf to non-minimal-stage instance in order to + // 1. avoid writing it by `cffuCompleteOnTimeout` and is able to read its result(`getSuccessNow`) + // 2. ensure that the returned cf is not minimal-stage CF instance(UnsupportedOperationException) + final CompletableFuture f = toNonMinCfCopy(requireNonNull(cfs[0], "cf1 is null")); + return cffuCompleteOnTimeout(f, valueIfNotSuccess, executorWhenTimeout, timeout, unit) + .handle((unused, ex) -> arrayList(getSuccessNow(f, valueIfNotSuccess))); + } + + // MUST be non-minimal-stage CF instances in order to read results(`getSuccessNow`), + // otherwise UnsupportedOperationException + final CompletableFuture[] cfArray = f_toNonMinCfArray(cfs); + return cffuCompleteOnTimeout(CompletableFuture.allOf(cfArray), null, executorWhenTimeout, timeout, unit) + .handle((unused, ex) -> arrayList(MGetSuccessNow0(valueIfNotSuccess, cfArray))); } /** - * 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. + * Multi-Gets(MGet) the results in the same order of the given cfs arguments, + * use the result value if the given stage is completed successfully, else use 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) + * @param cfs MUST be *Non-Minimal* CF instances in order to read results(`getSuccessNow`), + * otherwise UnsupportedOperationException */ - @SafeVarargs - public static CompletableFuture> mSupplyMostSuccessAsync( - @Nullable T valueIfNotSuccess, long timeout, TimeUnit unit, Supplier... suppliers) { - return mSupplyMostSuccessAsync(valueIfNotSuccess, AsyncPoolHolder.ASYNC_POOL, timeout, unit, suppliers); + @SuppressWarnings("unchecked") + private static T[] MGetSuccessNow0(@Nullable Object valueIfNotSuccess, CompletableFuture... cfs) { + Object[] ret = new Object[cfs.length]; + for (int i = 0; i < cfs.length; i++) { + ret[i] = getSuccessNow(cfs[i], valueIfNotSuccess); + } + return (T[]) ret; } /** - * Returns a new CompletableFuture that is asynchronously completed - * by tasks running in the given Executor 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. + * Returns a new CompletableFuture with the results in the same order of the given stages arguments, + * the new CompletableFuture is completed when all the given stages complete; + * If any of the given stages complete exceptionally, then the returned CompletableFuture also does so, + * with a CompletionException holding this exception as its cause. + * If no stages are provided, returns a CompletableFuture completed with the value empty list. *

- * If the given supplier is successful in the given time, the return result is the completed value; - * Otherwise the given valueIfNotSuccess. + * This method is the same as {@link #allOf(CompletionStage[])}, + * except that the returned CompletableFuture contains the results of the given stages. * - * @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 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, Executor, long, TimeUnit, CompletionStage[]) - * @see CompletableFuture#supplyAsync(Supplier, Executor) + * @param cfs the stages + * @return a new CompletableFuture that is completed when all the given stages complete + * @throws NullPointerException if the array or any of its elements are {@code null} + * @see #allResultsOfFastFail(CompletionStage[]) + * @see #allOf(CompletionStage[]) */ + @Contract(pure = true) @SafeVarargs - public static CompletableFuture> mSupplyMostSuccessAsync( - @Nullable T valueIfNotSuccess, Executor executor, long timeout, TimeUnit unit, - Supplier... suppliers) { - requireNonNull(executor, "executor is null"); - requireNonNull(unit, "unit is null"); - requireArrayAndEleNonNull("supplier", suppliers); + public static CompletableFuture> allResultsOf(CompletionStage... cfs) { + requireCfsAndEleNonNull(cfs); + final int len = cfs.length; + if (len == 0) return completedFuture(arrayList()); + // Defensive copy input cf to non-minimal-stage instance(toNonMinCfCopy) for SINGLE input + // in order to ensure that the returned cf is not minimal-stage CF instance(UnsupportedOperationException) + if (len == 1) return toNonMinCfCopy(cfs[0]).thenApply(CompletableFutureUtils::arrayList); - return mostResultsOfSuccess(valueIfNotSuccess, executor, timeout, unit, wrapSuppliers(executor, suppliers)); - } + final Object[] result = new Object[len]; + final CompletableFuture[] resultSetterCfs = createResultSetterCfs(cfs, result); - private static CompletableFuture[] wrapSuppliers( - Executor executor, Supplier[] suppliers) { - @SuppressWarnings("unchecked") - CompletableFuture[] cfs = new CompletableFuture[suppliers.length]; - for (int i = 0; i < suppliers.length; i++) { - cfs[i] = CompletableFuture.supplyAsync(suppliers[i], executor); - } - return cfs; + CompletableFuture> ret = CompletableFuture.allOf(resultSetterCfs) + .thenApply(unused -> arrayList(result)); + return f_cast(ret); } - //////////////////////////////////////////////////////////////////////////////// - //# allOf*/mostResultsOfSuccess methods - //////////////////////////////////////////////////////////////////////////////// - /** * Returns a new CompletableFuture that is completed when all the given stages complete; * If any of the given stages complete exceptionally, then the returned CompletableFuture also does so, @@ -320,40 +480,6 @@ public static CompletableFuture allOf(CompletionStage... cfs) { return CompletableFuture.allOf(f_toCfArray(cfs)); } - /** - * Returns a new CompletableFuture with the results in the same order of the given stages arguments, - * the new CompletableFuture is completed when all the given stages complete; - * If any of the given stages complete exceptionally, then the returned CompletableFuture also does so, - * with a CompletionException holding this exception as its cause. - * If no stages are provided, returns a CompletableFuture completed with the value empty list. - *

- * This method is the same as {@link #allOf(CompletionStage[])}, - * except that the returned CompletableFuture contains the results of the given stages. - * - * @param cfs the stages - * @return a new CompletableFuture that is completed when all the given stages complete - * @throws NullPointerException if the array or any of its elements are {@code null} - * @see #allResultsOfFastFail(CompletionStage[]) - * @see #allOf(CompletionStage[]) - */ - @Contract(pure = true) - @SafeVarargs - public static CompletableFuture> allResultsOf(CompletionStage... cfs) { - requireCfsAndEleNonNull(cfs); - final int len = cfs.length; - if (len == 0) return completedFuture(arrayList()); - // Defensive copy input cf to non-minimal-stage instance(toNonMinCfCopy) for SINGLE input - // in order to ensure that the returned cf is not minimal-stage CF instance(UnsupportedOperationException) - if (len == 1) return toNonMinCfCopy(cfs[0]).thenApply(CompletableFutureUtils::arrayList); - - final Object[] result = new Object[len]; - final CompletableFuture[] resultSetterCfs = createResultSetterCfs(cfs, result); - - CompletableFuture> ret = CompletableFuture.allOf(resultSetterCfs) - .thenApply(unused -> arrayList(result)); - return f_cast(ret); - } - /** * Returns a new CompletableFuture that is successful when all the given stages success; * If any of the given stages complete exceptionally, then the returned CompletableFuture also does so @@ -419,122 +545,6 @@ public static CompletableFuture allOfFastFail(CompletionStage... cfs) { return f_cast(ret); } - /** - * Returns a new CompletableFuture that is successful with the results in the same order - * of the given stages arguments when all the given stages success; - * If any of the given stages complete exceptionally, then the returned CompletableFuture also does so - * *without* waiting other incomplete given stages, with a CompletionException holding this exception as its cause. - * If no stages are provided, returns a CompletableFuture completed with the value empty list. - *

- * This method is the same as {@link #allResultsOf(CompletionStage[])} except for the fast-fail behavior. - *

- * This method is the same as {@link #allOfFastFail(CompletionStage[])}, - * except that the returned CompletableFuture contains the results of the given stages. - * - * @param cfs the stages - * @return a new CompletableFuture that is successful when all the given stages success - * @throws NullPointerException if the array or any of its elements are {@code null} - * @see #allResultsOf(CompletionStage[]) - * @see #allOfFastFail(CompletionStage[]) - * @see #allOf(CompletionStage[]) - */ - @Contract(pure = true) - @SafeVarargs - public static CompletableFuture> allResultsOfFastFail(CompletionStage... cfs) { - requireCfsAndEleNonNull(cfs); - final int len = cfs.length; - if (len == 0) return completedFuture(arrayList()); - // Defensive copy input cf to non-minimal-stage instance(toNonMinCfCopy) for SINGLE input - // in order to ensure that the returned cf is not minimal-stage CF instance(UnsupportedOperationException) - if (len == 1) return toNonMinCfCopy(cfs[0]).thenApply(CompletableFutureUtils::arrayList); - - final CompletableFuture[] successOrBeIncomplete = new CompletableFuture[len]; - // NOTE: fill ONE MORE element of failedOrBeIncomplete LATER - final CompletableFuture[] failedOrBeIncomplete = new CompletableFuture[len + 1]; - fill(cfs, successOrBeIncomplete, failedOrBeIncomplete); - - // NOTE: fill the ONE MORE element of failedOrBeIncomplete HERE: - // a cf that is successful when all given cfs success, otherwise be incomplete - failedOrBeIncomplete[len] = allResultsOf(successOrBeIncomplete); - - CompletableFuture ret = CompletableFuture.anyOf(failedOrBeIncomplete); - return f_cast(ret); - } - - /** - * Returns a new CompletableFuture with the most results in the same order of - * the given stages arguments in the given time({@code timeout}, aka as many results as possible in the given time). - *

- * If the given stage is successful, its 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 cfs the stages - * @see #getSuccessNow(CompletableFuture, Object) - */ - @Contract(pure = true) - @SafeVarargs - public static CompletableFuture> mostResultsOfSuccess( - @Nullable T valueIfNotSuccess, long timeout, TimeUnit unit, CompletionStage... cfs) { - return mostResultsOfSuccess(valueIfNotSuccess, AsyncPoolHolder.ASYNC_POOL, timeout, unit, cfs); - } - - /** - * Returns a new CompletableFuture with the most results in the same order of - * the given stages arguments in the given time({@code timeout}, aka as many results as possible in the given time). - *

- * If the given stage is successful, its result is the completed value; Otherwise the given valueIfNotSuccess. - * - * @param valueIfNotSuccess the value to return if not completed successfully - * @param executorWhenTimeout the async executor when triggered by timeout - * @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 cfs the stages - * @see #getSuccessNow(CompletableFuture, Object) - */ - @Contract(pure = true) - @SafeVarargs - public static CompletableFuture> mostResultsOfSuccess( - @Nullable T valueIfNotSuccess, Executor executorWhenTimeout, long timeout, TimeUnit unit, - CompletionStage... cfs) { - requireNonNull(executorWhenTimeout, "executorWhenTimeout is null"); - requireNonNull(unit, "unit is null"); - requireNonNull(cfs, "cfs is null"); - - if (cfs.length == 0) return completedFuture(arrayList()); - if (cfs.length == 1) { - // Defensive copy input cf to non-minimal-stage instance in order to - // 1. avoid writing it by `cffuCompleteOnTimeout` and is able to read its result(`getSuccessNow`) - // 2. ensure that the returned cf is not minimal-stage CF instance(UnsupportedOperationException) - final CompletableFuture f = toNonMinCfCopy(requireNonNull(cfs[0], "cf1 is null")); - return cffuCompleteOnTimeout(f, valueIfNotSuccess, executorWhenTimeout, timeout, unit) - .handle((unused, ex) -> arrayList(getSuccessNow(f, valueIfNotSuccess))); - } - - // MUST be non-minimal-stage CF instances in order to read results(`getSuccessNow`), - // otherwise UnsupportedOperationException - final CompletableFuture[] cfArray = f_toNonMinCfArray(cfs); - return cffuCompleteOnTimeout(CompletableFuture.allOf(cfArray), null, executorWhenTimeout, timeout, unit) - .handle((unused, ex) -> arrayList(MGetSuccessNow0(valueIfNotSuccess, cfArray))); - } - - /** - * Multi-Gets(MGet) the results in the same order of the given cfs arguments, - * use the result value if the given stage is completed successfully, else use the given valueIfNotSuccess - * - * @param cfs MUST be *Non-Minimal* CF instances in order to read results(`getSuccessNow`), - * otherwise UnsupportedOperationException - */ - @SuppressWarnings("unchecked") - private static T[] MGetSuccessNow0(@Nullable Object valueIfNotSuccess, CompletableFuture... cfs) { - Object[] ret = new Object[cfs.length]; - for (int i = 0; i < cfs.length; i++) { - ret[i] = getSuccessNow(cfs[i], valueIfNotSuccess); - } - return (T[]) ret; - } - @SafeVarargs private static > S[] requireCfsAndEleNonNull(S... css) { return requireArrayAndEleNonNull("cf", css); @@ -655,39 +665,10 @@ private static boolean isMinStageCf(CompletableFuture cf) { return "java.util.concurrent.CompletableFuture$MinimalStage".equals(cf.getClass().getName()); } - //////////////////////////////////////////////////////////////////////////////// - //# anyOf* methods - //////////////////////////////////////////////////////////////////////////////// - - /** - * Returns a new CompletableFuture that is completed when any of the given stages complete, with the same result. - * Otherwise, if it completed exceptionally, the returned CompletableFuture also does so, - * with a CompletionException holding this exception as its cause. - * If no stages are provided, returns an incomplete CompletableFuture. - *

- * This method is the same as {@link CompletableFuture#anyOf(CompletableFuture[])}, - * except that the parameter type is more generic {@link CompletionStage} instead of {@link CompletableFuture}, - * and the return type is more specific {@code T} instead of {@code Object}. - * - * @param cfs the stages - * @return a new CompletableFuture that is completed with the result or exception - * from any of the given stages when one completes - * @throws NullPointerException if the array or any of its elements are {@code null} - * @see #anyOfSuccess(CompletionStage[]) - * @see CompletableFuture#anyOf(CompletableFuture[]) - */ - @Contract(pure = true) - @SafeVarargs - public static CompletableFuture anyOf(CompletionStage... cfs) { - requireNonNull(cfs, "cfs is null"); - if (cfs.length == 0) return new CompletableFuture<>(); - // Defensive copy input cf to non-minimal-stage instance for SINGLE input in order to ensure that - // 1. avoid writing the input cf unexpectedly it by caller code - // 2. the returned cf is not minimal-stage CF instance(UnsupportedOperationException) - if (cfs.length == 1) return toNonMinCfCopy(requireNonNull(cfs[0], "cf1 is null")); - CompletableFuture ret = CompletableFuture.anyOf(f_toCfArray(cfs)); - return f_cast(ret); - } + // endregion + //////////////////////////////////////////////////////////// + // region## anyOf* Methods + //////////////////////////////////////////////////////////// /** * Returns a new CompletableFuture that is successful when any of the given stages success, @@ -729,25 +710,41 @@ public static CompletableFuture anyOfSuccess(CompletionStage return f_cast(ret); } - //////////////////////////////////////////////////////////////////////////////// - //# allTupleOf*/mostTupleOfSuccess methods - //////////////////////////////////////////////////////////////////////////////// - /** - * Returns a new CompletableFuture that is completed when the given two stages complete. - * If any of the given stages complete exceptionally, then the returned CompletableFuture also does so, + * Returns a new CompletableFuture that is completed when any of the given stages complete, with the same result. + * Otherwise, if it completed exceptionally, the returned CompletableFuture also does so, * with a CompletionException holding this exception as its cause. + * If no stages are provided, returns an incomplete CompletableFuture. + *

+ * This method is the same as {@link CompletableFuture#anyOf(CompletableFuture[])}, + * except that the parameter type is more generic {@link CompletionStage} instead of {@link CompletableFuture}, + * and the return type is more specific {@code T} instead of {@code Object}. * - * @return a new CompletableFuture that is completed when the given two stages complete - * @throws NullPointerException if any of the given stages are {@code null} - * @see #allResultsOf(CompletionStage[]) + * @param cfs the stages + * @return a new CompletableFuture that is completed with the result or exception + * from any of the given stages when one completes + * @throws NullPointerException if the array or any of its elements are {@code null} + * @see #anyOfSuccess(CompletionStage[]) + * @see CompletableFuture#anyOf(CompletableFuture[]) */ @Contract(pure = true) - public static CompletableFuture> allTupleOf( - CompletionStage cf1, CompletionStage cf2) { - return allTupleOf0(requireCfsAndEleNonNull(cf1, cf2), false); + @SafeVarargs + public static CompletableFuture anyOf(CompletionStage... cfs) { + requireNonNull(cfs, "cfs is null"); + if (cfs.length == 0) return new CompletableFuture<>(); + // Defensive copy input cf to non-minimal-stage instance for SINGLE input in order to ensure that + // 1. avoid writing the input cf unexpectedly it by caller code + // 2. the returned cf is not minimal-stage CF instance(UnsupportedOperationException) + if (cfs.length == 1) return toNonMinCfCopy(requireNonNull(cfs[0], "cf1 is null")); + CompletableFuture ret = CompletableFuture.anyOf(f_toCfArray(cfs)); + return f_cast(ret); } + // endregion + //////////////////////////////////////////////////////////// + // region## allTupleOf*/mostTupleOfSuccess Methods + //////////////////////////////////////////////////////////// + /** * Returns a new CompletableFuture that is successful when the given two stages success. * If any of the given stages complete exceptionally, then the returned CompletableFuture also does so @@ -767,18 +764,18 @@ public static CompletableFuture> allTupleOfFastFail( } /** - * Returns a new CompletableFuture that is completed when the given three stages complete. + * Returns a new CompletableFuture that is completed when the given two stages complete. * If any of the given stages 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 three stages complete + * @return a new CompletableFuture that is completed when the given two stages complete * @throws NullPointerException if any of the given stages are {@code null} * @see #allResultsOf(CompletionStage[]) */ @Contract(pure = true) - public static CompletableFuture> allTupleOf( - CompletionStage cf1, CompletionStage cf2, CompletionStage cf3) { - return allTupleOf0(requireCfsAndEleNonNull(cf1, cf2, cf3), false); + public static CompletableFuture> allTupleOf( + CompletionStage cf1, CompletionStage cf2) { + return allTupleOf0(requireCfsAndEleNonNull(cf1, cf2), false); } /** @@ -800,19 +797,18 @@ public static CompletableFuture> allTupleOfFastF } /** - * Returns a new CompletableFuture that is completed when the given four stages complete. + * Returns a new CompletableFuture that is completed when the given three stages complete. * If any of the given stages 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 four stages complete + * @return a new CompletableFuture that is completed when the given three stages complete * @throws NullPointerException if any of the given stages are {@code null} * @see #allResultsOf(CompletionStage[]) */ @Contract(pure = true) - public static CompletableFuture> allTupleOf( - CompletionStage cf1, CompletionStage cf2, - CompletionStage cf3, CompletionStage cf4) { - return allTupleOf0(requireCfsAndEleNonNull(cf1, cf2, cf3, cf4), false); + public static CompletableFuture> allTupleOf( + CompletionStage cf1, CompletionStage cf2, CompletionStage cf3) { + return allTupleOf0(requireCfsAndEleNonNull(cf1, cf2, cf3), false); } /** @@ -835,19 +831,19 @@ public static CompletableFuture> allTupl } /** - * Returns a new CompletableFuture that is completed when the given five stages complete. + * Returns a new CompletableFuture that is completed when the given four stages complete. * If any of the given stages 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 five stages complete + * @return a new CompletableFuture that is completed when the given four stages complete * @throws NullPointerException if any of the given stages are {@code null} * @see #allResultsOf(CompletionStage[]) */ @Contract(pure = true) - public static CompletableFuture> allTupleOf( - CompletionStage cf1, CompletionStage cf2, CompletionStage cf3, - CompletionStage cf4, CompletionStage cf5) { - return allTupleOf0(requireCfsAndEleNonNull(cf1, cf2, cf3, cf4, cf5), false); + public static CompletableFuture> allTupleOf( + CompletionStage cf1, CompletionStage cf2, + CompletionStage cf3, CompletionStage cf4) { + return allTupleOf0(requireCfsAndEleNonNull(cf1, cf2, cf3, cf4), false); } /** @@ -869,6 +865,22 @@ public static CompletableFuture> return allTupleOf0(requireCfsAndEleNonNull(cf1, cf2, cf3, cf4, cf5), true); } + /** + * Returns a new CompletableFuture that is completed when the given five stages complete. + * If any of the given stages 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 five stages complete + * @throws NullPointerException if any of the given stages are {@code null} + * @see #allResultsOf(CompletionStage[]) + */ + @Contract(pure = true) + public static CompletableFuture> allTupleOf( + CompletionStage cf1, CompletionStage cf2, CompletionStage cf3, + CompletionStage cf4, CompletionStage cf5) { + return allTupleOf0(requireCfsAndEleNonNull(cf1, cf2, cf3, cf4, cf5), false); + } + private static CompletableFuture allTupleOf0(CompletionStage[] css, boolean fastFail) { final Object[] result = new Object[css.length]; final CompletableFuture[] resultSetterCfs = createResultSetterCfs(css, result); @@ -1061,191 +1073,134 @@ private static CompletableFuture mostTupleOfSuccess0( .handle((unused, ex) -> tupleOf0(MGetSuccessNow0(null, cfArray))); } - //////////////////////////////////////////////////////////////////////////////// - //# then-multi-actions(M*) methods - // - // - thenMRun*Async(Runnable): Runnable* -> CompletableFuture - // thenMRunAsync / thenMRunFastFailAsync - // - thenMAccept*Async(Supplier): Consumer* -> CompletableFuture - // thenMAcceptAsync / thenMAcceptFastFailAsync - // - thenMApply*Async(Supplier): Function* -> CompletableFuture> - // thenMApplyAsync / thenMApplyFastFailAsync / thenMApplyMostSuccessAsync - //////////////////////////////////////////////////////////////////////////////// - - /** - * Returns a new CompletableFuture 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 CompletableFuture - * @return the new CompletableFuture - */ - public static CompletableFuture thenMRunAsync(CompletionStage cf, Runnable... actions) { - return thenMRunAsync(cf, AsyncPoolHolder.ASYNC_POOL, actions); - } + // endregion + //////////////////////////////////////////////////////////// + // region## Immediate Value Argument Factory Methods(backport methods) + //////////////////////////////////////////////////////////// /** - * Returns a new CompletableFuture that, when the given stage completes normally, - * executes the given actions using the given Executor. + * Returns a new CompletableFuture that is already completed exceptionally with the given exception. * - * @param actions the actions to perform before completing the returned CompletableFuture - * @return the new CompletableFuture + * @param ex the exception + * @param the type of the value + * @return the exceptionally completed CompletableFuture */ - public static CompletableFuture thenMRunAsync(CompletionStage cf, Executor executor, Runnable... actions) { - requireNonNull(cf, "cf is null"); - requireNonNull(executor, "executor is null"); - requireArrayAndEleNonNull("action", actions); - - return toNonMinCf(cf).thenCompose(unused -> CompletableFuture.allOf(wrapActions(executor, actions))); + @Contract(pure = true) + public static CompletableFuture failedFuture(Throwable ex) { + requireNonNull(ex, "ex is null"); + if (IS_JAVA9_PLUS) { + return CompletableFuture.failedFuture(ex); + } + final CompletableFuture cf = new CompletableFuture<>(); + cf.completeExceptionally(ex); + return cf; } /** - * Returns a new CompletableFuture that, when the given stage completes normally, - * executes the given actions using the CompletableFuture's default asynchronous execution facility. + * Returns a new CompletionStage that is already completed with the given value + * and supports only those methods in interface {@link CompletionStage}. *

- * This method is the same as {@link #thenMRunAsync(CompletionStage, Runnable...)} - * except for the fast-fail behavior. + * CAUTION:
+ * if run on old Java 8, just return a *normal* CompletableFuture which is NOT with a *minimal* CompletionStage. * - * @param actions the actions to perform before completing the returned CompletableFuture - * @return the new CompletableFuture + * @param value the value + * @param the type of the value + * @return the completed CompletionStage */ - public static CompletableFuture thenMRunFastFailAsync(CompletionStage cf, Runnable... actions) { - return thenMRunFastFailAsync(cf, AsyncPoolHolder.ASYNC_POOL, actions); + @Contract(pure = true) + public static CompletionStage completedStage(@Nullable T value) { + if (IS_JAVA9_PLUS) { + return CompletableFuture.completedStage(value); + } + return completedFuture(value); } /** - * Returns a new CompletableFuture that, when the given stage completes normally, - * executes the given actions using the given Executor. + * Returns a new CompletionStage that is already completed exceptionally with + * the given exception and supports only those methods in interface {@link CompletionStage}. *

- * 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 - * @return the new CompletableFuture - */ - public static CompletableFuture thenMRunFastFailAsync( - CompletionStage cf, Executor executor, Runnable... actions) { - requireNonNull(cf, "cf is null"); - requireNonNull(executor, "executor is null"); - requireArrayAndEleNonNull("action", actions); - - return toNonMinCf(cf).thenCompose(unused -> allOfFastFail(wrapActions(executor, actions))); - } - - /** - * Returns a new CompletableFuture 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 CompletableFuture - * @return the new CompletableFuture - */ - @SafeVarargs - public static CompletableFuture thenMAcceptAsync( - CompletionStage cf, Consumer... actions) { - return thenMAcceptAsync(cf, AsyncPoolHolder.ASYNC_POOL, actions); - } - - /** - * 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. + * CAUTION:
+ * if run on old Java 8, just return a *normal* CompletableFuture which is NOT with a *minimal* CompletionStage. * - * @param actions the actions to perform before completing the returned CompletableFuture - * @return the new CompletableFuture + * @param ex the exception + * @param the type of the value + * @return the exceptionally completed CompletionStage */ - @SafeVarargs - public static CompletableFuture thenMAcceptAsync( - CompletionStage cf, Executor executor, Consumer... actions) { - requireNonNull(cf, "cf is null"); - requireNonNull(executor, "executor is null"); - requireArrayAndEleNonNull("action", actions); - - return toNonMinCf(cf).thenCompose(v -> CompletableFuture.allOf(wrapConsumers(executor, v, actions))); + @Contract(pure = true) + public static CompletionStage failedStage(Throwable ex) { + if (IS_JAVA9_PLUS) { + return CompletableFuture.failedStage(ex); + } + return failedFuture(ex); } - /** - * Returns a new CompletableFuture 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 CompletableFuture - * @return the new CompletableFuture - */ - @SafeVarargs - public static CompletableFuture thenMAcceptFastFailAsync( - CompletionStage cf, Consumer... actions) { - return thenMAcceptFastFailAsync(cf, AsyncPoolHolder.ASYNC_POOL, actions); - } + // endregion + //////////////////////////////////////////////////////////// + // region## Delay Execution(backport methods) + //////////////////////////////////////////////////////////// /** - * 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. - *

- * This method is the same as {@link #thenMAcceptAsync(CompletionStage, Executor, Consumer[])} - * except for the fast-fail behavior. + * 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 actions the actions to perform before completing the returned CompletableFuture - * @return the new CompletableFuture + * @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 */ - @SafeVarargs - public static CompletableFuture thenMAcceptFastFailAsync( - CompletionStage cf, Executor executor, Consumer... actions) { - requireNonNull(cf, "cf is null"); - requireNonNull(executor, "executor is null"); - requireArrayAndEleNonNull("action", actions); - - return toNonMinCf(cf).thenCompose(v -> allOfFastFail(wrapConsumers(executor, v, actions))); - } - - private static CompletableFuture[] wrapConsumers(Executor executor, T v, Consumer[] actions) { - @SuppressWarnings("unchecked") - CompletableFuture[] cfs = new CompletableFuture[actions.length]; - for (int i = 0; i < actions.length; i++) { - final int idx = i; - cfs[idx] = CompletableFuture.runAsync(() -> actions[idx].accept(v), executor); - } - return cfs; + @Contract(pure = true) + public static Executor delayedExecutor(long delay, TimeUnit unit) { + return delayedExecutor(delay, unit, AsyncPoolHolder.ASYNC_POOL); } /** - * Returns a new CompletableFuture 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. + * 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 fns the functions to use to compute the values of the returned CompletableFuture - * @param the functions' return type - * @return the new CompletableFuture + * @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 */ - @SafeVarargs - public static CompletableFuture> thenMApplyAsync( - CompletionStage cf, Function... fns) { - return thenMApplyAsync(cf, AsyncPoolHolder.ASYNC_POOL, fns); + @Contract(pure = true) + public static Executor delayedExecutor(long delay, TimeUnit unit, Executor executor) { + requireNonNull(unit, "unit is null"); + requireNonNull(executor, "executor is null"); + if (IS_JAVA9_PLUS) { + return CompletableFuture.delayedExecutor(delay, unit, executor); + } + return new DelayedExecutor(delay, unit, executor); } /** - * Returns a new CompletableFuture 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. + * Returns the default Executor used for async methods that do not specify an Executor. + * This class uses the {@link ForkJoinPool#commonPool()} if it supports more than one parallel thread, + * or else an Executor using one thread per async task.
+ * CAUTION: This executor may be not suitable for common biz use(io intensive). * - * @param fns the functions to use to compute the values of the returned CompletableFuture - * @param the functions' return type - * @return the new CompletableFuture + * @return the executor */ - @SafeVarargs - public static CompletableFuture> thenMApplyAsync( - CompletionStage cf, Executor executor, Function... fns) { - requireNonNull(cf, "cf is null"); - requireNonNull(executor, "executor is null"); - requireArrayAndEleNonNull("fn", fns); - - return toNonMinCf(cf).thenCompose(v -> allResultsOf(wrapFunctions(executor, v, fns))); + @Contract(pure = true) + public static Executor defaultExecutor() { + return AsyncPoolHolder.ASYNC_POOL; } + // endregion + // endregion + //////////////////////////////////////////////////////////////////////////////// + // region# CF Instance Methods(including new enhanced + backport methods) + //////////////////////////////////////////////////////////////////////////////// + + //////////////////////////////////////////////////////////// + // region## Then-Multi-Actions(M*) Methods + // + // - thenMApply*Async(Function): Function* -> CompletableFuture> + // thenMApplyAsync / thenMApplyFastFailAsync / thenMApplyMostSuccessAsync + // - thenMAccept*Async(Supplier): Consumer* -> CompletableFuture + // thenMAcceptAsync / thenMAcceptFastFailAsync + // - thenMRun*Async(Runnable): Runnable* -> CompletableFuture + // thenMRunAsync / thenMRunFastFailAsync + //////////////////////////////////////////////////////////// + /** * Returns a new CompletableFuture that, when the given stage completes normally, * is executed using the CompletableFuture's default asynchronous execution facility, @@ -1345,6 +1300,43 @@ valueIfNotSuccess, executor, timeout, unit, 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 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 CompletableFuture + * @param the functions' return type + * @return the new CompletableFuture + */ + @SafeVarargs + public static CompletableFuture> thenMApplyAsync( + CompletionStage cf, Function... fns) { + return thenMApplyAsync(cf, AsyncPoolHolder.ASYNC_POOL, fns); + } + + /** + * Returns a new CompletableFuture 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 CompletableFuture + * @param the functions' return type + * @return the new CompletableFuture + */ + @SafeVarargs + public static CompletableFuture> thenMApplyAsync( + CompletionStage cf, Executor executor, Function... fns) { + requireNonNull(cf, "cf is null"); + requireNonNull(executor, "executor is null"); + requireArrayAndEleNonNull("fn", fns); + + return toNonMinCf(cf).thenCompose(v -> allResultsOf(wrapFunctions(executor, v, fns))); + } + private static CompletableFuture[] wrapFunctions( Executor executor, T v, Function[] fns) { @SuppressWarnings("unchecked") @@ -1356,154 +1348,160 @@ private static CompletableFuture[] wrapFunctions( return cfs; } - //////////////////////////////////////////////////////////////////////////////// - //# `then both(binary input)` methods with fast-fail support: - // - // - runAfterBothFastFail*(Runnable): Void, Void -> Void - // - thenAcceptBothFastFail*(BiConsumer): (T1, T2) -> Void - // - thenCombineFastFail*(BiFunction): (T1, T2) -> U - //////////////////////////////////////////////////////////////////////////////// + /** + * Returns a new CompletableFuture 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 CompletableFuture + * @return the new CompletableFuture + */ + @SafeVarargs + public static CompletableFuture thenMAcceptAsync( + CompletionStage cf, Consumer... actions) { + return thenMAcceptAsync(cf, AsyncPoolHolder.ASYNC_POOL, actions); + } /** - * Returns a new CompletableFuture that, when two given stages both complete normally, executes the given action. - * if any of the given stage complete exceptionally, then the returned CompletableFuture also does so - * *without* waiting other incomplete given CompletionStage, - * with a CompletionException holding this exception as its cause. - *

- * This method is the same as {@link CompletionStage#runAfterBoth(CompletionStage, Runnable)} - * except for the fast-fail behavior. + * 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 action the action to perform before completing the returned CompletableFuture + * @param actions the actions to perform before completing the returned CompletableFuture * @return the new CompletableFuture - * @see CompletionStage#runAfterBoth(CompletionStage, Runnable) */ - public static CompletableFuture runAfterBothFastFail( - CompletionStage cf1, CompletionStage cf2, Runnable action) { - final CompletionStage[] css = requireCfsAndEleNonNull(cf1, cf2); - requireNonNull(action, "action is null"); + @SafeVarargs + public static CompletableFuture thenMAcceptAsync( + CompletionStage cf, Executor executor, Consumer... actions) { + requireNonNull(cf, "cf is null"); + requireNonNull(executor, "executor is null"); + requireArrayAndEleNonNull("action", actions); - return allOfFastFail(css).thenRun(action); + return toNonMinCf(cf).thenCompose(v -> CompletableFuture.allOf(wrapConsumers(executor, v, actions))); } /** - * Returns a new CompletableFuture that, when two given stages both complete normally, - * executes the given action using CompletableFuture's default asynchronous execution facility. - * if any of the given stage complete exceptionally, then the returned CompletableFuture also does so - * *without* waiting other incomplete given CompletionStage, - * with a CompletionException holding this exception as its cause. + * Returns a new CompletableFuture 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 CompletionStage#runAfterBothAsync(CompletionStage, Runnable)} + * This method is the same as {@link #thenMAcceptAsync(CompletionStage, Consumer[])} * except for the fast-fail behavior. * - * @param action the action to perform before completing the returned CompletableFuture + * @param actions the actions to perform before completing the returned CompletableFuture * @return the new CompletableFuture - * @see CompletionStage#runAfterBothAsync(CompletionStage, Runnable) */ - public static CompletableFuture runAfterBothFastFailAsync( - CompletionStage cf1, CompletionStage cf2, Runnable action) { - return runAfterBothFastFailAsync(cf1, cf2, action, AsyncPoolHolder.ASYNC_POOL); + @SafeVarargs + public static CompletableFuture thenMAcceptFastFailAsync( + CompletionStage cf, Consumer... actions) { + return thenMAcceptFastFailAsync(cf, AsyncPoolHolder.ASYNC_POOL, actions); } /** - * Returns a new CompletableFuture that, when two given stages both complete normally, - * executes the given action using the supplied executor. - * if any of the given stage complete exceptionally, then the returned CompletableFuture also does so - * *without* waiting other incomplete given CompletionStage, - * with a CompletionException holding this exception as its cause. + * 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. *

- * This method is the same as {@link CompletionStage#runAfterBothAsync(CompletionStage, Runnable, Executor)} + * This method is the same as {@link #thenMAcceptAsync(CompletionStage, Executor, Consumer[])} * except for the fast-fail behavior. * - * @param action the action to perform before completing the returned CompletableFuture + * @param actions the actions to perform before completing the returned CompletableFuture * @return the new CompletableFuture - * @see CompletionStage#runAfterBothAsync(CompletionStage, Runnable, Executor) */ - public static CompletableFuture runAfterBothFastFailAsync( - CompletionStage cf1, CompletionStage cf2, Runnable action, Executor executor) { - final CompletionStage[] css = requireCfsAndEleNonNull(cf1, cf2); - requireNonNull(action, "action is null"); + @SafeVarargs + public static CompletableFuture thenMAcceptFastFailAsync( + CompletionStage cf, Executor executor, Consumer... actions) { + requireNonNull(cf, "cf is null"); requireNonNull(executor, "executor is null"); + requireArrayAndEleNonNull("action", actions); - return allOfFastFail(css).thenRunAsync(action, executor); + return toNonMinCf(cf).thenCompose(v -> allOfFastFail(wrapConsumers(executor, v, actions))); + } + + private static CompletableFuture[] wrapConsumers(Executor executor, T v, Consumer[] actions) { + @SuppressWarnings("unchecked") + CompletableFuture[] cfs = new CompletableFuture[actions.length]; + for (int i = 0; i < actions.length; i++) { + final int idx = i; + cfs[idx] = CompletableFuture.runAsync(() -> actions[idx].accept(v), executor); + } + return cfs; } /** - * Returns a new CompletableFuture that, when tow given stage both complete normally, - * is executed with the two results as arguments to the supplied action. - * if any of the given stage complete exceptionally, then the returned CompletableFuture also does so - * *without* waiting other incomplete given CompletionStage, - * with a CompletionException holding this exception as its cause. + * Returns a new CompletableFuture 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 CompletionStage#thenAcceptBoth(CompletionStage, BiConsumer)} + * This method is the same as {@link #thenMRunAsync(CompletionStage, Runnable...)} * except for the fast-fail behavior. * - * @param action the action to perform before completing the returned CompletableFuture + * @param actions the actions to perform before completing the returned CompletableFuture * @return the new CompletableFuture - * @see CompletionStage#thenAcceptBoth(CompletionStage, BiConsumer) + * @see CompletableFuture#thenRunAsync(Runnable) + * @see #allOfFastFail(CompletionStage[]) */ - @SuppressWarnings("unchecked") - public static CompletableFuture thenAcceptBothFastFail( - CompletionStage cf1, CompletionStage cf2, - BiConsumer action) { - final CompletionStage[] css = requireCfsAndEleNonNull(cf1, cf2); - requireNonNull(action, "action is null"); - - final Object[] result = new Object[css.length]; - final CompletableFuture[] resultSetterCfs = createResultSetterCfs(css, result); - - return allOfFastFail(resultSetterCfs).thenRun(() -> action.accept((T) result[0], (U) result[1])); + public static CompletableFuture thenMRunFastFailAsync(CompletionStage cf, Runnable... actions) { + return thenMRunFastFailAsync(cf, AsyncPoolHolder.ASYNC_POOL, actions); } /** - * Returns a new CompletableFuture that, when tow given stage both complete normally, - * is executed using CompletableFuture's default asynchronous execution facility, - * with the two results as arguments to the supplied action. - * if any of the given stage complete exceptionally, then the returned CompletableFuture also does so - * *without* waiting other incomplete given CompletionStage, - * with a CompletionException holding this exception as its cause. + * Returns a new CompletableFuture that, when the given stage completes normally, + * executes the given actions using the given Executor. *

- * This method is the same as {@link CompletionStage#thenAcceptBothAsync(CompletionStage, BiConsumer)} + * This method is the same as {@link #thenMRunAsync(CompletionStage, Executor, Runnable...)} * except for the fast-fail behavior. * - * @param action the action to perform before completing the returned CompletableFuture + * @param actions the actions to perform before completing the returned CompletableFuture * @return the new CompletableFuture - * @see CompletionStage#thenAcceptBothAsync(CompletionStage, BiConsumer) + * @see CompletableFuture#thenRunAsync(Runnable, Executor) + * @see #allOfFastFail(CompletionStage[]) */ - public static CompletableFuture thenAcceptBothFastFailAsync( - CompletionStage cf1, CompletionStage cf2, - BiConsumer action) { - return thenAcceptBothFastFailAsync(cf1, cf2, action, AsyncPoolHolder.ASYNC_POOL); + public static CompletableFuture thenMRunFastFailAsync( + CompletionStage cf, Executor executor, Runnable... actions) { + requireNonNull(cf, "cf is null"); + requireNonNull(executor, "executor is null"); + requireArrayAndEleNonNull("action", actions); + + return toNonMinCf(cf).thenCompose(unused -> allOfFastFail(wrapActions(executor, actions))); } /** - * Returns a new CompletableFuture that, when tow given stage both complete normally, - * is executed using the supplied executor, - * with the two results as arguments to the supplied action. - * if any of the given stage complete exceptionally, then the returned CompletableFuture also does so - * *without* waiting other incomplete given CompletionStage, - * with a CompletionException holding this exception as its cause. - *

- * This method is the same as {@link CompletionStage#thenAcceptBothAsync(CompletionStage, BiConsumer, Executor)} - * except for the fast-fail behavior. + * Returns a new CompletableFuture that, when the given stage completes normally, + * executes the given actions using the given Executor. * - * @param action the action to perform before completing the returned CompletableFuture + * @param actions the actions to perform before completing the returned CompletableFuture * @return the new CompletableFuture - * @see CompletionStage#thenAcceptBothAsync(CompletionStage, BiConsumer, Executor) + * @see CompletableFuture#thenRunAsync(Runnable, Executor) + * @see #allOf(CompletionStage[]) */ - @SuppressWarnings("unchecked") - public static CompletableFuture thenAcceptBothFastFailAsync( - CompletionStage cf1, CompletionStage cf2, - BiConsumer action, Executor executor) { - final CompletionStage[] css = requireCfsAndEleNonNull(cf1, cf2); - requireNonNull(action, "action is null"); + public static CompletableFuture thenMRunAsync(CompletionStage cf, Executor executor, Runnable... actions) { + requireNonNull(cf, "cf is null"); requireNonNull(executor, "executor is null"); + requireArrayAndEleNonNull("action", actions); - final Object[] result = new Object[css.length]; - final CompletableFuture[] resultSetterCfs = createResultSetterCfs(css, result); + return toNonMinCf(cf).thenCompose(unused -> CompletableFuture.allOf(wrapActions(executor, actions))); + } - return allOfFastFail(resultSetterCfs).thenRunAsync(() -> action.accept((T) result[0], (U) result[1]), executor); + /** + * Returns a new CompletableFuture 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 CompletableFuture + * @return the new CompletableFuture + * @see CompletableFuture#thenRunAsync(Runnable) + * @see #allOf(CompletionStage[]) + */ + public static CompletableFuture thenMRunAsync(CompletionStage cf, Runnable... actions) { + return thenMRunAsync(cf, AsyncPoolHolder.ASYNC_POOL, actions); } + // endregion + //////////////////////////////////////////////////////////// + // region## thenBoth* Methods(binary input) with fast-fail support + // + // - thenCombineFastFail*(BiFunction): (T1, T2) -> U + // - thenAcceptBothFastFail*(BiConsumer): (T1, T2) -> Void + // - runAfterBothFastFail*(Runnable): Void, Void -> Void + //////////////////////////////////////////////////////////// + /** * Returns a new CompletableFuture that, when tow given stage both complete normally, * is executed with the two results as arguments to the supplied function. @@ -1582,135 +1580,155 @@ public static CompletableFuture thenCombineFastFailAsync( .thenApplyAsync(unused -> fn.apply((T) result[0], (U) result[1]), executor); } - //////////////////////////////////////////////////////////////////////////////// - //# `then either(binary input)` methods with either(any)-success support: - // - // - runAfterEitherSuccess*(Runnable): Void, Void -> Void - // - acceptEitherSuccess*(Consumer): (T, T) -> Void - // - applyToEitherSuccess*(Function): (T, T) -> U - //////////////////////////////////////////////////////////////////////////////// - /** - * Returns a new CompletableFuture that, when either given stage success, executes the given action. - * Otherwise, all two given CompletionStage complete exceptionally, - * the returned CompletableFuture also does so, with a CompletionException holding - * an exception from any of the given CompletionStage as its cause. + * Returns a new CompletableFuture that, when tow given stage both complete normally, + * is executed with the two results as arguments to the supplied action. + * if any of the given stage complete exceptionally, then the returned CompletableFuture also does so + * *without* waiting other incomplete given CompletionStage, + * with a CompletionException holding this exception as its cause. *

- * This method is the same as {@link CompletionStage#runAfterEither(CompletionStage, Runnable)} - * except for the either-success behavior instead of either-complete. + * This method is the same as {@link CompletionStage#thenAcceptBoth(CompletionStage, BiConsumer)} + * except for the fast-fail behavior. * * @param action the action to perform before completing the returned CompletableFuture * @return the new CompletableFuture - * @see CompletionStage#runAfterEither(CompletionStage, Runnable) + * @see CompletionStage#thenAcceptBoth(CompletionStage, BiConsumer) */ - public static CompletableFuture runAfterEitherSuccess( - CompletionStage cf1, CompletionStage cf2, Runnable action) { + @SuppressWarnings("unchecked") + public static CompletableFuture thenAcceptBothFastFail( + CompletionStage cf1, CompletionStage cf2, + BiConsumer action) { final CompletionStage[] css = requireCfsAndEleNonNull(cf1, cf2); requireNonNull(action, "action is null"); - return anyOfSuccess(css).thenRun(action); + final Object[] result = new Object[css.length]; + final CompletableFuture[] resultSetterCfs = createResultSetterCfs(css, result); + + return allOfFastFail(resultSetterCfs).thenRun(() -> action.accept((T) result[0], (U) result[1])); } /** - * Returns a new CompletableFuture that, when either given stage success, executes the given action - * using CompletableFuture's default asynchronous execution facility. - * Otherwise, all two given CompletionStage complete exceptionally, - * the returned CompletableFuture also does so, with a CompletionException holding - * an exception from any of the given CompletionStage as its cause. + * Returns a new CompletableFuture that, when tow given stage both complete normally, + * is executed using CompletableFuture's default asynchronous execution facility, + * with the two results as arguments to the supplied action. + * if any of the given stage complete exceptionally, then the returned CompletableFuture also does so + * *without* waiting other incomplete given CompletionStage, + * with a CompletionException holding this exception as its cause. *

- * This method is the same as {@link CompletionStage#runAfterEitherAsync(CompletionStage, Runnable)} - * except for the either-success behavior instead of either-complete. + * This method is the same as {@link CompletionStage#thenAcceptBothAsync(CompletionStage, BiConsumer)} + * except for the fast-fail behavior. * * @param action the action to perform before completing the returned CompletableFuture * @return the new CompletableFuture - * @see CompletionStage#runAfterEitherAsync(CompletionStage, Runnable) + * @see CompletionStage#thenAcceptBothAsync(CompletionStage, BiConsumer) */ - public static CompletableFuture runAfterEitherSuccessAsync( - CompletionStage cf1, CompletionStage cf2, Runnable action) { - return runAfterEitherSuccessAsync(cf1, cf2, action, AsyncPoolHolder.ASYNC_POOL); + public static CompletableFuture thenAcceptBothFastFailAsync( + CompletionStage cf1, CompletionStage cf2, + BiConsumer action) { + return thenAcceptBothFastFailAsync(cf1, cf2, action, AsyncPoolHolder.ASYNC_POOL); } /** - * Returns a new CompletableFuture that, when either given stage success, executes the given action - * using the supplied executor. - * Otherwise, all two given CompletionStage complete exceptionally, - * the returned CompletableFuture also does so, with a CompletionException holding - * an exception from any of the given CompletionStage as its cause. + * Returns a new CompletableFuture that, when tow given stage both complete normally, + * is executed using the supplied executor, + * with the two results as arguments to the supplied action. + * if any of the given stage complete exceptionally, then the returned CompletableFuture also does so + * *without* waiting other incomplete given CompletionStage, + * with a CompletionException holding this exception as its cause. *

- * This method is the same as {@link CompletionStage#runAfterEitherAsync(CompletionStage, Runnable, Executor)} - * except for the either-success behavior instead of either-complete. + * This method is the same as {@link CompletionStage#thenAcceptBothAsync(CompletionStage, BiConsumer, Executor)} + * except for the fast-fail behavior. * * @param action the action to perform before completing the returned CompletableFuture * @return the new CompletableFuture - * @see CompletionStage#runAfterEitherAsync(CompletionStage, Runnable, Executor) + * @see CompletionStage#thenAcceptBothAsync(CompletionStage, BiConsumer, Executor) */ - public static CompletableFuture runAfterEitherSuccessAsync( - CompletionStage cf1, CompletionStage cf2, Runnable action, Executor executor) { + @SuppressWarnings("unchecked") + public static CompletableFuture thenAcceptBothFastFailAsync( + CompletionStage cf1, CompletionStage cf2, + BiConsumer action, Executor executor) { final CompletionStage[] css = requireCfsAndEleNonNull(cf1, cf2); requireNonNull(action, "action is null"); requireNonNull(executor, "executor is null"); - return anyOfSuccess(css).thenRunAsync(action, executor); + final Object[] result = new Object[css.length]; + final CompletableFuture[] resultSetterCfs = createResultSetterCfs(css, result); + + return allOfFastFail(resultSetterCfs).thenRunAsync(() -> action.accept((T) result[0], (U) result[1]), executor); } /** - * Returns a new CompletableFuture that, when either given stage success, - * is executed with the corresponding result as argument to the supplied action. + * Returns a new CompletableFuture that, when two given stages both complete normally, executes the given action. + * if any of the given stage complete exceptionally, then the returned CompletableFuture also does so + * *without* waiting other incomplete given CompletionStage, + * with a CompletionException holding this exception as its cause. *

- * This method is the same as {@link CompletionStage#acceptEither(CompletionStage, Consumer)} - * except for the either-success behavior instead of either-complete. + * This method is the same as {@link CompletionStage#runAfterBoth(CompletionStage, Runnable)} + * except for the fast-fail behavior. * * @param action the action to perform before completing the returned CompletableFuture * @return the new CompletableFuture - * @see CompletionStage#acceptEither(CompletionStage, Consumer) + * @see CompletionStage#runAfterBoth(CompletionStage, Runnable) */ - public static CompletableFuture acceptEitherSuccess( - CompletionStage cf1, CompletionStage cf2, Consumer action) { - final CompletionStage[] css = requireCfsAndEleNonNull(cf1, cf2); + public static CompletableFuture runAfterBothFastFail( + CompletionStage cf1, CompletionStage cf2, Runnable action) { + final CompletionStage[] css = requireCfsAndEleNonNull(cf1, cf2); requireNonNull(action, "action is null"); - return anyOfSuccess(css).thenAccept(action); + return allOfFastFail(css).thenRun(action); } /** - * Returns a new CompletableFuture that, when either given stage success, - * is executed using this CompletableFuture's default asynchronous execution facility, - * with the corresponding result as argument to the supplied action. + * Returns a new CompletableFuture that, when two given stages both complete normally, + * executes the given action using CompletableFuture's default asynchronous execution facility. + * if any of the given stage complete exceptionally, then the returned CompletableFuture also does so + * *without* waiting other incomplete given CompletionStage, + * with a CompletionException holding this exception as its cause. *

- * This method is the same as {@link CompletionStage#acceptEitherAsync(CompletionStage, Consumer)} - * except for the either-success behavior instead of either-complete. + * This method is the same as {@link CompletionStage#runAfterBothAsync(CompletionStage, Runnable)} + * except for the fast-fail behavior. * * @param action the action to perform before completing the returned CompletableFuture * @return the new CompletableFuture - * @see CompletionStage#acceptEitherAsync(CompletionStage, Consumer) + * @see CompletionStage#runAfterBothAsync(CompletionStage, Runnable) */ - public static CompletableFuture acceptEitherSuccessAsync( - CompletionStage cf1, CompletionStage cf2, Consumer action) { - return acceptEitherSuccessAsync(cf1, cf2, action, AsyncPoolHolder.ASYNC_POOL); + public static CompletableFuture runAfterBothFastFailAsync( + CompletionStage cf1, CompletionStage cf2, Runnable action) { + return runAfterBothFastFailAsync(cf1, cf2, action, AsyncPoolHolder.ASYNC_POOL); } /** - * Returns a new CompletableFuture that, when either given stage success, - * is executed using the supplied executor, with the corresponding result as argument to the supplied action. + * Returns a new CompletableFuture that, when two given stages both complete normally, + * executes the given action using the supplied executor. + * if any of the given stage complete exceptionally, then the returned CompletableFuture also does so + * *without* waiting other incomplete given CompletionStage, + * with a CompletionException holding this exception as its cause. *

- * This method is the same as {@link CompletionStage#acceptEitherAsync(CompletionStage, Consumer, Executor)} - * except for the either-success behavior instead of either-complete. + * This method is the same as {@link CompletionStage#runAfterBothAsync(CompletionStage, Runnable, Executor)} + * except for the fast-fail behavior. * - * @param action the action to perform before completing the returned CompletableFuture - * @param executor the executor to use for asynchronous execution + * @param action the action to perform before completing the returned CompletableFuture * @return the new CompletableFuture - * @see CompletionStage#acceptEitherAsync(CompletionStage, Consumer, Executor) + * @see CompletionStage#runAfterBothAsync(CompletionStage, Runnable, Executor) */ - public static CompletableFuture acceptEitherSuccessAsync( - CompletionStage cf1, CompletionStage cf2, - Consumer action, Executor executor) { - final CompletionStage[] css = requireCfsAndEleNonNull(cf1, cf2); + public static CompletableFuture runAfterBothFastFailAsync( + CompletionStage cf1, CompletionStage cf2, Runnable action, Executor executor) { + final CompletionStage[] css = requireCfsAndEleNonNull(cf1, cf2); requireNonNull(action, "action is null"); requireNonNull(executor, "executor is null"); - return anyOfSuccess(css).thenAcceptAsync(action, executor); + return allOfFastFail(css).thenRunAsync(action, executor); } + // endregion + //////////////////////////////////////////////////////////// + // region## thenEither Methods(binary input) with either(any)-success support + // + // - applyToEitherSuccess*(Function): (T, T) -> U + // - acceptEitherSuccess*(Consumer): (T, T) -> Void + // - runAfterEitherSuccess*(Runnable): Void, Void -> Void + //////////////////////////////////////////////////////////// + /** * Returns a new CompletableFuture that, when either given stage success, * is executed with the corresponding result as argument to the supplied function. @@ -1772,201 +1790,131 @@ public static CompletableFuture applyToEitherSuccessAsync( return anyOfSuccess(css).thenApplyAsync(fn, executor); } - //////////////////////////////////////////////////////////////////////////////// - //# New enhanced methods - //////////////////////////////////////////////////////////////////////////////// - - /** - * Peeks the result by executing the given action when given stage completes, returns the given stage. - *

- * When the given stage is complete, the given action is invoked with the result (or {@code null} if none) - * and the exception (or {@code null} if none) of given stage as arguments. Whether the supplied action - * throws an exception or not, the given stage is NOT affected. - *

- * Unlike method {@link CompletionStage#handle handle} and like method - * {@link CompletionStage#whenComplete(BiConsumer) whenComplete}, - * this method is not designed to translate completion outcomes. - * - * @param action the action to perform - * @return the given stage - * @see CompletionStage#whenComplete(BiConsumer) - * @see java.util.stream.Stream#peek(Consumer) - */ - public static > - C peek(C cf, BiConsumer action) { - requireNonNull(cf, "cf is null"); - requireNonNull(action, "action is null"); - - cf.whenComplete(action).exceptionally(ex -> reportException("Exception occurred in the action of peek:", ex)); - return cf; - } - - /** - * Peeks the result by executing the given action when given stage completes, - * executes the given action using given stage's default asynchronous execution facility, - * returns the given stage. - *

- * When the given stage is complete, the given action is invoked with the result (or {@code null} if none) - * and the exception (or {@code null} if none) of given stage as arguments. Whether the supplied action - * throws an exception or not, the given stage is NOT affected. - *

- * Unlike method {@link CompletionStage#handle handle} and like method - * {@link CompletionStage#whenComplete(BiConsumer) whenComplete}, - * this method is not designed to translate completion outcomes. - * - * @param action the action to perform - * @return the given stage - * @see CompletionStage#whenCompleteAsync(BiConsumer) - * @see java.util.stream.Stream#peek(Consumer) - */ - public static > - C peekAsync(C cf, BiConsumer action) { - return peekAsync(cf, action, AsyncPoolHolder.ASYNC_POOL); - } - /** - * Peeks the result by executing the given action when given stage completes, - * executes the given action using the supplied Executor, returns the given stage. - *

- * When the given stage is complete, the given action is invoked with the result (or {@code null} if none) - * and the exception (or {@code null} if none) of given stage as arguments. Whether the supplied action - * throws an exception or not, the given stage is NOT affected. + * Returns a new CompletableFuture that, when either given stage success, + * is executed with the corresponding result as argument to the supplied action. *

- * Unlike method {@link CompletionStage#handle handle} and like method - * {@link CompletionStage#whenComplete(BiConsumer) whenComplete}, - * this method is not designed to translate completion outcomes. - * - * @param action the action to perform - * @return the given stage - * @see CompletionStage#whenCompleteAsync(BiConsumer, Executor) - * @see java.util.stream.Stream#peek(Consumer) - */ - public static > - C peekAsync(C cf, BiConsumer action, Executor executor) { - requireNonNull(cf, "cf is null"); - requireNonNull(action, "action is null"); - requireNonNull(executor, "executor is null"); - - cf.whenCompleteAsync(action, executor).exceptionally(ex -> - reportException("Exception occurred in the action of peekAsync:", ex)); - return cf; - } - - @Nullable - @SuppressWarnings("SameReturnValue") - private static T reportException(String msg, Throwable ex) { - StringWriter sw = new StringWriter(4096); - PrintWriter writer = new PrintWriter(sw); - - writer.println(msg); - ex.printStackTrace(writer); + * This method is the same as {@link CompletionStage#acceptEither(CompletionStage, Consumer)} + * except for the either-success behavior instead of either-complete. + * + * @param action the action to perform before completing the returned CompletableFuture + * @return the new CompletableFuture + * @see CompletionStage#acceptEither(CompletionStage, Consumer) + */ + public static CompletableFuture acceptEitherSuccess( + CompletionStage cf1, CompletionStage cf2, Consumer action) { + final CompletionStage[] css = requireCfsAndEleNonNull(cf1, cf2); + requireNonNull(action, "action is null"); - System.err.println(sw); - return null; + return anyOfSuccess(css).thenAccept(action); } - //////////////////////////////////////////////////////////////////////////////// - //# Backport CF static methods + related enhanced methods - // compatibility for low Java versions - //////////////////////////////////////////////////////////////////////////////// - - //# Factory methods - /** - * Returns a new CompletableFuture that is already completed exceptionally with the given exception. + * Returns a new CompletableFuture that, when either given stage success, + * is executed using this CompletableFuture's default asynchronous execution facility, + * with the corresponding result as argument to the supplied action. + *

+ * This method is the same as {@link CompletionStage#acceptEitherAsync(CompletionStage, Consumer)} + * except for the either-success behavior instead of either-complete. * - * @param ex the exception - * @param the type of the value - * @return the exceptionally completed CompletableFuture + * @param action the action to perform before completing the returned CompletableFuture + * @return the new CompletableFuture + * @see CompletionStage#acceptEitherAsync(CompletionStage, Consumer) */ - @Contract(pure = true) - public static CompletableFuture failedFuture(Throwable ex) { - requireNonNull(ex, "ex is null"); - if (IS_JAVA9_PLUS) { - return CompletableFuture.failedFuture(ex); - } - final CompletableFuture cf = new CompletableFuture<>(); - cf.completeExceptionally(ex); - return cf; + public static CompletableFuture acceptEitherSuccessAsync( + CompletionStage cf1, CompletionStage cf2, Consumer action) { + return acceptEitherSuccessAsync(cf1, cf2, action, AsyncPoolHolder.ASYNC_POOL); } /** - * Returns a new CompletionStage that is already completed with the given value - * and supports only those methods in interface {@link CompletionStage}. + * Returns a new CompletableFuture that, when either given stage success, + * is executed using the supplied executor, with the corresponding result as argument to the supplied action. *

- * CAUTION:
- * if run on old Java 8, just return a *normal* CompletableFuture which is NOT with a *minimal* CompletionStage. + * This method is the same as {@link CompletionStage#acceptEitherAsync(CompletionStage, Consumer, Executor)} + * except for the either-success behavior instead of either-complete. * - * @param value the value - * @param the type of the value - * @return the completed CompletionStage + * @param action the action to perform before completing the returned CompletableFuture + * @param executor the executor to use for asynchronous execution + * @return the new CompletableFuture + * @see CompletionStage#acceptEitherAsync(CompletionStage, Consumer, Executor) */ - @Contract(pure = true) - public static CompletionStage completedStage(@Nullable T value) { - if (IS_JAVA9_PLUS) { - return CompletableFuture.completedStage(value); - } - return completedFuture(value); + public static CompletableFuture acceptEitherSuccessAsync( + CompletionStage cf1, CompletionStage cf2, + Consumer action, Executor executor) { + final CompletionStage[] css = requireCfsAndEleNonNull(cf1, cf2); + requireNonNull(action, "action is null"); + requireNonNull(executor, "executor is null"); + + return anyOfSuccess(css).thenAcceptAsync(action, executor); } /** - * Returns a new CompletionStage that is already completed exceptionally with - * the given exception and supports only those methods in interface {@link CompletionStage}. + * Returns a new CompletableFuture that, when either given stage success, executes the given action. + * Otherwise, all two given CompletionStage complete exceptionally, + * the returned CompletableFuture also does so, with a CompletionException holding + * an exception from any of the given CompletionStage as its cause. *

- * CAUTION:
- * if run on old Java 8, just return a *normal* CompletableFuture which is NOT with a *minimal* CompletionStage. + * This method is the same as {@link CompletionStage#runAfterEither(CompletionStage, Runnable)} + * except for the either-success behavior instead of either-complete. * - * @param ex the exception - * @param the type of the value - * @return the exceptionally completed CompletionStage + * @param action the action to perform before completing the returned CompletableFuture + * @return the new CompletableFuture + * @see CompletionStage#runAfterEither(CompletionStage, Runnable) */ - @Contract(pure = true) - public static CompletionStage failedStage(Throwable ex) { - if (IS_JAVA9_PLUS) { - return CompletableFuture.failedStage(ex); - } - return failedFuture(ex); - } + public static CompletableFuture runAfterEitherSuccess( + CompletionStage cf1, CompletionStage cf2, Runnable action) { + final CompletionStage[] css = requireCfsAndEleNonNull(cf1, cf2); + requireNonNull(action, "action is null"); - //# Delay Execution + return anyOfSuccess(css).thenRun(action); + } /** - * 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. + * Returns a new CompletableFuture that, when either given stage success, executes the given action + * using CompletableFuture's default asynchronous execution facility. + * Otherwise, all two given CompletionStage complete exceptionally, + * the returned CompletableFuture also does so, with a CompletionException holding + * an exception from any of the given CompletionStage as its cause. + *

+ * This method is the same as {@link CompletionStage#runAfterEitherAsync(CompletionStage, Runnable)} + * except for the either-success behavior instead of either-complete. * - * @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 + * @param action the action to perform before completing the returned CompletableFuture + * @return the new CompletableFuture + * @see CompletionStage#runAfterEitherAsync(CompletionStage, Runnable) */ - @Contract(pure = true) - public static Executor delayedExecutor(long delay, TimeUnit unit) { - return delayedExecutor(delay, unit, AsyncPoolHolder.ASYNC_POOL); + public static CompletableFuture runAfterEitherSuccessAsync( + CompletionStage cf1, CompletionStage cf2, Runnable action) { + return runAfterEitherSuccessAsync(cf1, cf2, action, AsyncPoolHolder.ASYNC_POOL); } /** - * 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. + * Returns a new CompletableFuture that, when either given stage success, executes the given action + * using the supplied executor. + * Otherwise, all two given CompletionStage complete exceptionally, + * the returned CompletableFuture also does so, with a CompletionException holding + * an exception from any of the given CompletionStage as its cause. + *

+ * This method is the same as {@link CompletionStage#runAfterEitherAsync(CompletionStage, Runnable, Executor)} + * except for the either-success behavior instead of either-complete. * - * @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 + * @param action the action to perform before completing the returned CompletableFuture + * @return the new CompletableFuture + * @see CompletionStage#runAfterEitherAsync(CompletionStage, Runnable, Executor) */ - @Contract(pure = true) - public static Executor delayedExecutor(long delay, TimeUnit unit, Executor executor) { - requireNonNull(unit, "unit is null"); + public static CompletableFuture runAfterEitherSuccessAsync( + CompletionStage cf1, CompletionStage cf2, Runnable action, Executor executor) { + final CompletionStage[] css = requireCfsAndEleNonNull(cf1, cf2); + requireNonNull(action, "action is null"); requireNonNull(executor, "executor is null"); - if (IS_JAVA9_PLUS) { - return CompletableFuture.delayedExecutor(delay, unit, executor); - } - return new DelayedExecutor(delay, unit, executor); - } - //////////////////////////////////////// - //# Backport CF instance methods - //////////////////////////////////////// + return anyOfSuccess(css).thenRunAsync(action, executor); + } - //# Error Handling methods of CompletionStage + // endregion + //////////////////////////////////////////////////////////// + // region## Error Handling Methods of CompletionStage + //////////////////////////////////////////////////////////// /** * Returns a new CompletionStage that, when given stage completes exceptionally, is executed with given @@ -2008,7 +1956,10 @@ C exceptionallyAsync(C cf, Function fn, Executor executo ).thenCompose(x -> x); } - //# Timeout Control methods + // endregion + //////////////////////////////////////////////////////////// + // region## Timeout Control Methods of CompletableFuture + //////////////////////////////////////////////////////////// /** * Exceptionally completes given CompletableFuture with a {@link TimeoutException} @@ -2187,7 +2138,10 @@ private static void completeCf(CompletableFuture cf, Object value, @Null } } - //# Advanced methods of CompletionStage + // endregion + //////////////////////////////////////////////////////////// + // region## Advanced Methods of CompletionStage + //////////////////////////////////////////////////////////// /** * Returns a new CompletableFuture that, when given CompletableFuture completes exceptionally, @@ -2247,7 +2201,99 @@ C exceptionallyComposeAsync(C cf, Function x); } - //# Read(explicitly) methods of CompletableFuture + /** + * Peeks the result by executing the given action when given stage completes, returns the given stage. + *

+ * When the given stage is complete, the given action is invoked with the result (or {@code null} if none) + * and the exception (or {@code null} if none) of given stage as arguments. Whether the supplied action + * throws an exception or not, the given stage is NOT affected. + *

+ * Unlike method {@link CompletionStage#handle handle} and like method + * {@link CompletionStage#whenComplete(BiConsumer) whenComplete}, + * this method is not designed to translate completion outcomes. + * + * @param action the action to perform + * @return the given stage + * @see CompletionStage#whenComplete(BiConsumer) + * @see java.util.stream.Stream#peek(Consumer) + */ + public static > + C peek(C cf, BiConsumer action) { + requireNonNull(cf, "cf is null"); + requireNonNull(action, "action is null"); + + cf.whenComplete(action).exceptionally(ex -> reportException("Exception occurred in the action of peek:", ex)); + return cf; + } + + /** + * Peeks the result by executing the given action when given stage completes, + * executes the given action using given stage's default asynchronous execution facility, + * returns the given stage. + *

+ * When the given stage is complete, the given action is invoked with the result (or {@code null} if none) + * and the exception (or {@code null} if none) of given stage as arguments. Whether the supplied action + * throws an exception or not, the given stage is NOT affected. + *

+ * Unlike method {@link CompletionStage#handle handle} and like method + * {@link CompletionStage#whenComplete(BiConsumer) whenComplete}, + * this method is not designed to translate completion outcomes. + * + * @param action the action to perform + * @return the given stage + * @see CompletionStage#whenCompleteAsync(BiConsumer) + * @see java.util.stream.Stream#peek(Consumer) + */ + public static > + C peekAsync(C cf, BiConsumer action) { + return peekAsync(cf, action, AsyncPoolHolder.ASYNC_POOL); + } + + /** + * Peeks the result by executing the given action when given stage completes, + * executes the given action using the supplied Executor, returns the given stage. + *

+ * When the given stage is complete, the given action is invoked with the result (or {@code null} if none) + * and the exception (or {@code null} if none) of given stage as arguments. Whether the supplied action + * throws an exception or not, the given stage is NOT affected. + *

+ * Unlike method {@link CompletionStage#handle handle} and like method + * {@link CompletionStage#whenComplete(BiConsumer) whenComplete}, + * this method is not designed to translate completion outcomes. + * + * @param action the action to perform + * @return the given stage + * @see CompletionStage#whenCompleteAsync(BiConsumer, Executor) + * @see java.util.stream.Stream#peek(Consumer) + */ + public static > + C peekAsync(C cf, BiConsumer action, Executor executor) { + requireNonNull(cf, "cf is null"); + requireNonNull(action, "action is null"); + requireNonNull(executor, "executor is null"); + + cf.whenCompleteAsync(action, executor).exceptionally(ex -> + reportException("Exception occurred in the action of peekAsync:", ex)); + return cf; + } + + @Nullable + @SuppressWarnings("SameReturnValue") + private static T reportException(String msg, Throwable ex) { + StringWriter sw = new StringWriter(4096); + PrintWriter writer = new PrintWriter(sw); + + writer.println(msg); + ex.printStackTrace(writer); + + System.err.println(sw); + return null; + } + + // endregion + //////////////////////////////////////////////////////////// + // region## Read(explicitly) Methods of CompletableFuture(including Future) + //////////////////////////////////////////////////////////// /** * Waits if necessary for at most the given time for the computation to complete, @@ -2447,7 +2493,10 @@ public static CffuState state(Future cf) { } } - //# Write methods of CompletableFuture + // endregion + //////////////////////////////////////////////////////////// + // region## Write Methods of CompletableFuture + //////////////////////////////////////////////////////////// /** * Completes given CompletableFuture with the result of the given Supplier function invoked @@ -2517,7 +2566,10 @@ C completeExceptionallyAsync(C cf, Supplier supplier, Execu return cf; } - //# Re-Config methods + // endregion + //////////////////////////////////////////////////////////// + // region## Re-Config Methods of CompletableFuture + //////////////////////////////////////////////////////////// /** * Returns a new CompletionStage that is completed normally with the same value as given CompletableFuture @@ -2573,23 +2625,10 @@ public static CompletableFuture newIncompleteFuture(CompletableFuture return new CompletableFuture<>(); } - //# Getter methods - - /** - * Returns the default Executor used for async methods that do not specify an Executor. - * This class uses the {@link ForkJoinPool#commonPool()} if it supports more than one parallel thread, - * or else an Executor using one thread per async task.
- * CAUTION: This executor may be not suitable for common biz use(io intensive). - * - * @return the executor - */ - @Contract(pure = true) - public static Executor defaultExecutor() { - return AsyncPoolHolder.ASYNC_POOL; - } - + // endregion + // endregion //////////////////////////////////////////////////////////////////////////////// - //# Conversion Methods + // region# Conversion Methods(static methods) // // - toCompletableFutureArray: CompletionStage[](including Cffu) -> CF[] // - completableFutureListToArray: List -> CF[] @@ -2629,8 +2668,9 @@ public static CompletableFuture[] completableFutureListToArray(List