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..95a33c77 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,68 @@ 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) */ + @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) */ + @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) */ + @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)); } /** @@ -108,7 +124,6 @@ public Cffu thenRunAsync(Runnable action, Executor executor) { * * @param action the action to perform before completing the returned Cffu * @return the new Cffu - * @see CompletionStage#thenAccept(Consumer) */ @Override public Cffu thenAccept(Consumer action) { @@ -124,7 +139,6 @@ public Cffu thenAccept(Consumer action) { * * @param action the action to perform before completing the returned Cffu * @return the new Cffu - * @see CompletionStage#thenAcceptAsync(Consumer) */ @Override public Cffu thenAcceptAsync(Consumer action) { @@ -140,7 +154,6 @@ public Cffu thenAcceptAsync(Consumer action) { * @param action the action to perform before completing the returned Cffu * @param executor the executor to use for asynchronous execution * @return the new Cffu - * @see CompletionStage#thenAcceptAsync(Consumer, Executor) */ @Override public Cffu thenAcceptAsync(Consumer action, Executor executor) { @@ -148,211 +161,172 @@ 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) */ - @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) */ - @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) */ - @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. - *

- * 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 - * @return the new Cffu - */ - @Override - 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, - * executes the given action using {@link #defaultExecutor()}. - *

- * 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 - * @return the new Cffu - */ - @Override - 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, - * executes the given action using the supplied executor. - *

- * 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 executor the executor to use for asynchronous execution - * @return the new Cffu - */ - @Override - 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, executes the given action. + * 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)); } /** * 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 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. *

- * See the {@link CompletionStage} documentation for rules covering exceptional completion. + * This method is the same as {@link #thenAcceptBoth(CompletionStage, BiConsumer)} + * except for the fast-fail behavior. * * @param other the other CompletionStage * @param action the action to perform before completing the returned Cffu * @param the type of the other CompletionStage's result * @return the new Cffu */ - @Override - public Cffu thenAcceptBoth( + public Cffu thenAcceptBothFastFail( CompletionStage other, BiConsumer action) { - return reset0(cf.thenAcceptBoth(other, action)); + return reset0(CompletableFutureUtils.thenAcceptBothFastFail(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 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. *

- * See the {@link CompletionStage} documentation for rules covering exceptional completion. + * This method is the same as {@link #thenAcceptBothAsync(CompletionStage, BiConsumer)} + * except for the fast-fail behavior. * * @param other the other CompletionStage * @param action the action to perform before completing the returned Cffu * @param the type of the other CompletionStage's result * @return the new Cffu */ - @Override - public Cffu thenAcceptBothAsync( + public Cffu thenAcceptBothFastFailAsync( CompletionStage other, BiConsumer action) { - return thenAcceptBothAsync(other, action, fac.defaultExecutor()); + return thenAcceptBothFastFailAsync(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 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. *

- * See the {@link CompletionStage} documentation for rules - * covering exceptional completion. + * This method is the same as {@link #thenAcceptBothAsync(CompletionStage, BiConsumer, Executor)} + * except for the fast-fail behavior. * * @param other the other CompletionStage * @param action the action to perform before completing the returned Cffu @@ -360,73 +334,64 @@ public Cffu thenAcceptBothAsync( * @param the type of the other CompletionStage's result * @return the new Cffu */ - @Override - public Cffu thenAcceptBothAsync(CompletionStage other, - BiConsumer action, - Executor executor) { - return reset0(cf.thenAcceptBothAsync(other, action, executor)); + public Cffu thenAcceptBothFastFailAsync(CompletionStage other, + BiConsumer action, + Executor executor) { + return reset0(CompletableFutureUtils.thenAcceptBothFastFailAsync(this, 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 action. + * 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 #thenAcceptBoth(CompletionStage, BiConsumer)} + * This method is the same as {@link #runAfterBoth(CompletionStage, Runnable)} * except for the fast-fail behavior. * * @param other the other CompletionStage * @param action the action to perform before completing the returned Cffu - * @param the type of the other CompletionStage's result * @return the new Cffu */ - public Cffu thenAcceptBothFastFail( - CompletionStage other, BiConsumer action) { - return reset0(CompletableFutureUtils.thenAcceptBothFastFail(this, other, action)); + 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 action. + * 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 #thenAcceptBothAsync(CompletionStage, BiConsumer)} + * This method is the same as {@link #runAfterBothAsync(CompletionStage, Runnable)} * except for the fast-fail behavior. * * @param other the other CompletionStage * @param action the action to perform before completing the returned Cffu - * @param the type of the other CompletionStage's result * @return the new Cffu */ - public Cffu thenAcceptBothFastFailAsync( - CompletionStage other, BiConsumer action) { - return thenAcceptBothFastFailAsync(other, action, 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 action. + * 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 #thenAcceptBothAsync(CompletionStage, BiConsumer, Executor)} + * This method is the same as {@link #runAfterBothAsync(CompletionStage, Runnable, Executor)} * except for the fast-fail behavior. * * @param other the other CompletionStage * @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 * @return the new Cffu */ - public Cffu thenAcceptBothFastFailAsync(CompletionStage other, - BiConsumer action, - Executor executor) { - return reset0(CompletableFutureUtils.thenAcceptBothFastFailAsync(this, other, action, executor)); + public Cffu runAfterBothFastFailAsync(CompletionStage other, Runnable action, Executor executor) { + return reset0(CompletableFutureUtils.runAfterBothFastFailAsync(this, other, action, executor)); } /** @@ -490,83 +455,60 @@ public Cffu thenCombineAsync(CompletionStage other, /** * 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. + * is executed with the two results as arguments to the supplied action. *

- * This method is the same as {@link #thenCombine(CompletionStage, BiFunction)} - * except for the fast-fail behavior. + * 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 + * @param the type of the other CompletionStage's result * @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)); + @Override + public Cffu thenAcceptBoth( + CompletionStage other, BiConsumer action) { + return reset0(cf.thenAcceptBoth(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. - * 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. + * is executed using {@link #defaultExecutor()}, with the two results as arguments to the supplied action. *

- * This method is the same as {@link #thenCombineAsync(CompletionStage, BiFunction)} - * except for the fast-fail behavior. + * 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 + * @param the type of the other CompletionStage's result * @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()); + @Override + public Cffu thenAcceptBothAsync( + CompletionStage other, BiConsumer action) { + return thenAcceptBothAsync(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. - * 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. + * is executed using the supplied executor, with the two results as arguments to the supplied action. *

- * This method is the same as {@link #thenCombineAsync(CompletionStage, BiFunction, Executor)} - * except for the fast-fail behavior. + * 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 `thenAcceptBothFastFailAsync`") - public Cffu thenCombineFastFailAsync(CompletionStage other, - BiFunction fn, - Executor executor) { - return reset0(CompletableFutureUtils.thenCombineFastFailAsync(this, other, fn, executor)); + @Override + public Cffu thenAcceptBothAsync(CompletionStage other, + BiConsumer action, + Executor executor) { + return reset0(cf.thenAcceptBothAsync(other, action, executor)); } - //////////////////////////////////////////////////////////////////////////////// - //# `then either(binary input)` methods of CompletionStage: - // - // - runAfterEither*(Runnable): Void, Void -> Void - // - acceptEither*(Consumer): (T, T) -> Void - // - applyToEither*(Function): (T, T) -> U - //////////////////////////////////////////////////////////////////////////////// - /** - * Returns a new Cffu that, when either this or the other given stage complete normally, - * executes the given action. + * 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. * @@ -575,27 +517,28 @@ public Cffu thenCombineFastFailAsync(CompletionStage othe * @return the new Cffu */ @Override - public Cffu runAfterEither(CompletionStage other, Runnable action) { - return reset0(cf.runAfterEither(other, action)); + public Cffu runAfterBoth(CompletionStage other, Runnable action) { + return reset0(cf.runAfterBoth(other, action)); } /** - * Returns a new Cffu that, when either this or the other given stage complete normally, + * Returns a new Cffu that, when this and the other given stage both complete normally, * 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 action the action to perform before completing the returned Cffu * @return the new Cffu */ @Override - public Cffu runAfterEitherAsync(CompletionStage other, Runnable action) { - return runAfterEitherAsync(other, action, fac.defaultExecutor()); + public Cffu runAfterBothAsync(CompletionStage other, Runnable action) { + return runAfterBothAsync(other, action, fac.defaultExecutor()); } /** - * Returns a new Cffu that, when either this or the other given stage complete normally, + * Returns a new Cffu that, when this and the other given stage both complete normally, * executes the given action using the supplied executor. *

* See the {@link CompletionStage} documentation for rules covering exceptional completion. @@ -606,77 +549,90 @@ public Cffu runAfterEitherAsync(CompletionStage other, Runnable action) * @return the new Cffu */ @Override - public Cffu runAfterEitherAsync( - CompletionStage other, Runnable action, Executor executor) { - return reset0(cf.runAfterEitherAsync(other, action, executor)); + public Cffu runAfterBothAsync(CompletionStage other, Runnable action, Executor executor) { + return reset0(cf.runAfterBothAsync(other, action, executor)); } + // endregion + //////////////////////////////////////////////////////////////////////////////// + // region# thenEither* Methods(binary input) of CompletionStage + // + // - 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. - * 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)); } /** * 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 action. *

- * See the {@link CompletionStage} documentation for rules covering exceptional completion. + * This method is the same as {@link #acceptEither(CompletionStage, Consumer)} + * 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 * @return the new Cffu */ - @Override - public Cffu acceptEither( + public Cffu acceptEitherSuccess( CompletionStage other, Consumer action) { - return reset0(cf.acceptEither(other, action)); + return reset0(CompletableFutureUtils.acceptEitherSuccess(this, other, action)); } /** @@ -684,74 +640,76 @@ public Cffu acceptEither( * is executed using {@link #defaultExecutor()}, * with the corresponding result as argument to the supplied action. *

- * See the {@link CompletionStage} documentation for rules covering exceptional completion. + * This method is the same as {@link #acceptEitherAsync(CompletionStage, Consumer)} + * 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 * @return the new Cffu */ - @Override - public Cffu acceptEitherAsync( + public Cffu acceptEitherSuccessAsync( CompletionStage other, Consumer action) { - return acceptEitherAsync(other, action, fac.defaultExecutor()); + return acceptEitherSuccessAsync(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 action. *

- * See the {@link CompletionStage} documentation for rules covering exceptional completion. + * This method is the same as {@link #acceptEitherAsync(CompletionStage, Consumer, 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 executor the executor to use for asynchronous execution * @return the new Cffu */ - @Override - public Cffu acceptEitherAsync(CompletionStage other, - Consumer action, - Executor executor) { - return reset0(cf.acceptEitherAsync(other, action, executor)); + public Cffu acceptEitherSuccessAsync(CompletionStage other, + Consumer action, + Executor executor) { + 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 action. + * 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 #acceptEither(CompletionStage, Consumer)} + * 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 action the action to perform before completing the returned Cffu * @return the new Cffu */ - public Cffu acceptEitherSuccess( - CompletionStage other, Consumer action) { - return reset0(CompletableFutureUtils.acceptEitherSuccess(this, other, action)); + 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 action. + * 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 #acceptEitherAsync(CompletionStage, Consumer)} + * 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 action the action to perform before completing the returned Cffu * @return the new Cffu */ - public Cffu acceptEitherSuccessAsync( - CompletionStage other, Consumer action) { - return acceptEitherSuccessAsync(other, action, 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 action. + * 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 #acceptEitherAsync(CompletionStage, Consumer, 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 @@ -759,10 +717,9 @@ public Cffu acceptEitherSuccessAsync( * @param executor the executor to use for asynchronous execution * @return the new Cffu */ - public Cffu acceptEitherSuccessAsync(CompletionStage other, - Consumer action, - Executor executor) { - return reset0(CompletableFutureUtils.acceptEitherSuccessAsync(this, other, action, executor)); + public Cffu runAfterEitherSuccessAsync( + CompletionStage other, Runnable action, Executor executor) { + return reset0(CompletableFutureUtils.runAfterEitherSuccessAsync(this, other, action, executor)); } /** @@ -824,65 +781,105 @@ public Cffu applyToEitherAsync(CompletionStage other, /** * 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. + * is executed with the corresponding result as argument to the supplied action. *

- * This method is the same as {@link #applyToEither(CompletionStage, Function)} - * except for the either-success behavior instead of either-complete. + * 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 `acceptEitherSuccess`") - public Cffu applyToEitherSuccess( - CompletionStage other, Function fn) { - return reset0(CompletableFutureUtils.applyToEitherSuccess(this, other, fn)); + @Override + public Cffu acceptEither( + CompletionStage other, Consumer action) { + return reset0(cf.acceptEither(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. + * with the corresponding result as argument to the supplied action. *

- * This method is the same as {@link #applyToEitherAsync(CompletionStage, Function)} - * except for the either-success behavior instead of either-complete. + * 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 `acceptEitherSuccessAsync`") - public Cffu applyToEitherSuccessAsync( - CompletionStage other, Function fn) { - return applyToEitherSuccessAsync(other, fn, fac.defaultExecutor()); + @Override + public Cffu acceptEitherAsync( + CompletionStage other, Consumer action) { + return acceptEitherAsync(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. + * is executed using the supplied executor, with the corresponding result as argument to the supplied action. *

- * This method is the same as {@link #applyToEitherAsync(CompletionStage, Function, Executor)} - * except for the either-success behavior instead of either-complete. + * 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 `acceptEitherSuccessAsync`") - public Cffu applyToEitherSuccessAsync(CompletionStage other, - Function fn, - Executor executor) { - return reset0(CompletableFutureUtils.applyToEitherSuccessAsync(this, other, fn, executor)); + @Override + public Cffu acceptEitherAsync(CompletionStage other, + Consumer action, + Executor executor) { + return reset0(cf.acceptEitherAsync(other, action, executor)); + } + + /** + * Returns a new Cffu that, when either this or the other given stage complete normally, + * executes the given action. + *

+ * 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 + * @return the new Cffu + */ + @Override + 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, + * executes the given action using {@link #defaultExecutor()}. + *

+ * 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 + * @return the new Cffu + */ + @Override + 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, + * executes the given action using the supplied executor. + *

+ * 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 executor the executor to use for asynchronous execution + * @return the new Cffu + */ + @Override + public Cffu runAfterEitherAsync( + CompletionStage other, Runnable action, Executor executor) { + return reset0(cf.runAfterEitherAsync(other, action, executor)); + } + + // endregion //////////////////////////////////////////////////////////////////////////////// - //# Error Handling methods of CompletionStage: - // - // - exceptionally*: throwable -> T + // region# Error Handling Methods of CompletionStage //////////////////////////////////////////////////////////////////////////////// /** @@ -932,11 +929,9 @@ public Cffu exceptionallyAsync(Function fn, Executor return reset0(CompletableFutureUtils.exceptionallyAsync(cf, fn, executor)); } + // endregion //////////////////////////////////////////////////////////////////////////////// - //# Timeout Control methods: - // - // - orTimeout: timeout event -> complete with the given value - // - completeOnTimeout: timeout event -> complete with TimeoutException + // region# Timeout Control Methods //////////////////////////////////////////////////////////////////////////////// /** @@ -1057,8 +1052,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 +1065,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*) //////////////////////////////////////////////////////////////////////////////// /** @@ -1331,7 +1327,6 @@ public Cffu whenCompleteAsync(BiConsumer action * * @param action the action to perform * @return this Cffu - * @see CompletionStage#whenComplete(BiConsumer) * @see java.util.stream.Stream#peek(Consumer) */ public Cffu peek(BiConsumer action) { @@ -1353,7 +1348,6 @@ public Cffu peek(BiConsumer action) { * * @param action the action to perform * @return this Cffu - * @see CompletionStage#whenCompleteAsync(BiConsumer) * @see java.util.stream.Stream#peek(Consumer) */ public Cffu peekAsync(BiConsumer action) { @@ -1374,7 +1368,6 @@ public Cffu peekAsync(BiConsumer action) { * * @param action the action to perform * @return this Cffu - * @see CompletionStage#whenCompleteAsync(BiConsumer) * @see java.util.stream.Stream#peek(Consumer) */ public Cffu peekAsync(BiConsumer action, Executor executor) { @@ -1382,8 +1375,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! @@ -1414,12 +1408,6 @@ public Cffu peekAsync(BiConsumer action, Execut * @throws CancellationException if the computation was cancelled * @throws ExecutionException if the computation threw an exception * @throws InterruptedException if the current thread was interrupted while waiting - * @see #join() - * @see #join(long, TimeUnit) - * @see #getNow(Object) - * @see #getSuccessNow(Object) - * @see #resultNow() - * @see #get(long, TimeUnit) */ @Blocking @Nullable @@ -1440,12 +1428,6 @@ public T get() throws InterruptedException, ExecutionException { * @throws ExecutionException if the computation threw an exception * @throws InterruptedException if the current thread was interrupted while waiting * @throws TimeoutException if the wait timed out - * @see #join(long, TimeUnit) - * @see #getNow(Object) - * @see #getSuccessNow(Object) - * @see #resultNow() - * @see #join() - * @see #get() */ @Blocking @Nullable @@ -1466,12 +1448,6 @@ public T get(long timeout, TimeUnit unit) throws InterruptedException, Execution * @throws CancellationException if the computation was cancelled * @throws CompletionException if this future completed exceptionally * or a completion computation threw an exception - * @see #join(long, TimeUnit) - * @see #getNow(Object) - * @see #getSuccessNow(Object) - * @see #resultNow() - * @see #get(long, TimeUnit) - * @see #get() */ @Blocking @Nullable @@ -1508,12 +1484,6 @@ public T join() { * @throws CompletionException if this future completed exceptionally * or a completion computation threw an exception * or the wait timed out(with the {@code TimeoutException} as its cause) - * @see #join() - * @see #getNow(Object) - * @see #getSuccessNow(Object) - * @see #resultNow() - * @see #get(long, TimeUnit) - * @see #get() * @see #orTimeout(long, TimeUnit) */ @Blocking @@ -1533,11 +1503,6 @@ public T join(long timeout, TimeUnit unit) { * @throws CompletionException if this future completed exceptionally * or a completion computation threw an exception * @see #getSuccessNow(Object) - * @see #resultNow() - * @see #join(long, TimeUnit) - * @see #join() - * @see #get(long, TimeUnit) - * @see #get() */ @Contract(pure = true) @Nullable @@ -1554,12 +1519,6 @@ public T getNow(T valueIfAbsent) { * * @param valueIfNotSuccess the value to return if not completed successfully * @return the result value, if completed successfully, else the given valueIfNotSuccess - * @see #getNow(Object) - * @see #resultNow() - * @see #join(long, TimeUnit) - * @see #join() - * @see #get(long, TimeUnit) - * @see #get() */ @Contract(pure = true) @Nullable @@ -1583,9 +1542,6 @@ public T getSuccessNow(@Nullable T valueIfNotSuccess) { * * @return the computed result * @throws IllegalStateException if the task has not completed or the task did not complete with a result - * @see #getNow(Object) - * @see #getSuccessNow(Object) - * @see #exceptionNow() */ @Contract(pure = true) @Nullable @@ -1603,8 +1559,6 @@ public T resultNow() { * @return the exception thrown by the task * @throws IllegalStateException if the task has not completed, the task completed normally, * or the task was cancelled - * @see #resultNow() - * @see #getNow(Object) * @see #getSuccessNow(Object) */ @Contract(pure = true) @@ -1667,8 +1621,6 @@ public boolean isCancelled() { * * @return the computation state * @see #cffuState() - * @see Future.State - * @see CompletableFuture#state() */ @Contract(pure = true) @Override @@ -1682,10 +1634,6 @@ public Future.State state() { * with java version compatibility logic, so you can invoke in old {@code java 18-}. * * @return the computation state - * @see CffuState - * @see Future.State - * @see Future#state() - * @see #state() */ @Contract(pure = true) public CffuState cffuState() { @@ -1693,14 +1641,9 @@ public CffuState cffuState() { return CompletableFutureUtils.state(cf); } + // endregion //////////////////////////////////////////////////////////////////////////////// - //# Write methods of CompletableFuture - // - // - complete(value): boolean - // - completeAsync*: -> Cffu - // - // - completeExceptionally(ex): boolean - // - cancel(boolean): boolean + // region# Write Methods //////////////////////////////////////////////////////////////////////////////// /** @@ -1790,14 +1733,9 @@ public boolean cancel(boolean mayInterruptIfRunning) { return cf.cancel(mayInterruptIfRunning); } + // endregion //////////////////////////////////////////////////////////////////////////////// - //# Cffu Re-Config methods - // - // - minimalCompletionStage() - // - resetCffuFactory(cffuFactory) - // - // - toCompletableFuture() - // - copy() + // region# Re-Config Methods //////////////////////////////////////////////////////////////////////////////// /** @@ -1819,7 +1757,6 @@ public boolean cancel(boolean mayInterruptIfRunning) { * } * * @see #resetCffuFactory(CffuFactory) - * @see CompletableFuture#minimalCompletionStage() */ @Contract(pure = true) public CompletionStage minimalCompletionStage() { @@ -1860,7 +1797,6 @@ public Cffu resetCffuFactory(CffuFactory cffuFactory) { * @return the CompletableFuture * @see #cffuUnwrap() * @see CompletableFutureUtils#toCompletableFutureArray(CompletionStage[]) - * @see CompletionStage#toCompletableFuture() */ @Contract(pure = true) @Override @@ -1882,12 +1818,9 @@ public Cffu copy() { return reset0(CompletableFutureUtils.copy(cf)); } + // endregion //////////////////////////////////////////////////////////////////////////////// - //# Getter methods of Cffu properties - // - // - defaultExecutor() - // - forbidObtrudeMethods() - // - isMinimalStage() + // region# Getter Methods of Cffu properties //////////////////////////////////////////////////////////////////////////////// /** @@ -1948,11 +1881,9 @@ public boolean isMinimalStage() { return isMinimalStage; } + // endregion //////////////////////////////////////////////////////////////////////////////// - //# Inspection methods of Cffu - // - // - cffuUnwrap() - // - getNumberOfDependents() + // region# Inspection Methods //////////////////////////////////////////////////////////////////////////////// /** @@ -1977,7 +1908,6 @@ public CompletableFuture cffuUnwrap() { * This method is designed for use in monitoring system state, not for synchronization control. * * @return the number of dependent Cffus - * @see CompletableFuture#getNumberOfDependents() */ @Contract(pure = true) public int getNumberOfDependents() { @@ -1985,14 +1915,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() //////////////////////////////////////////////////////////////////////////////// @@ -2040,7 +1970,6 @@ public void obtrudeException(Throwable ex) { * just return a Cffu with a *normal* underlying CompletableFuture which is NOT with a *minimal* CompletionStage. * * @see CffuFactory#newIncompleteCffu() - * @see CompletableFuture#newIncompleteFuture() */ @Contract(pure = true) public Cffu 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..d3240bfd 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,93 +75,61 @@ 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. + * In general, should not use this method in biz code, prefer other factory methods of Cffu. * - * @param value the value - * @param the type of the value - * @return the completed CompletionStage - * @see CompletableFuture#completedStage(Object) - * @see CompletableFuture#minimalCompletionStage() + * @see CompletableFuture#CompletableFuture() */ @Contract(pure = true) - public CompletionStage completedStage(@Nullable T value) { - return createMin((CompletableFuture) CompletableFutureUtils.completedStage(value)); + public Cffu newIncompleteCffu() { + return create(new CompletableFuture<>()); } + // endregion + //////////////////////////////////////////////////////////////////////////////// + // region# Factory Methods + //////////////////////////////////////////////////////////////////////////////// + + //////////////////////////////////////////////////////////////////////////////// + // region## supplyAsync*/runAsync* Methods(create by action) + //////////////////////////////////////////////////////////////////////////////// + /** - * Returns a new Cffu that is already completed exceptionally with the given exception. + * Returns a new Cffu that is asynchronously completed + * by a task running in the {@link #defaultExecutor()} with + * the value obtained by calling the given Supplier. * - * @param ex the exception - * @param the type of the value - * @return the exceptionally completed Cffu - * @see CompletableFuture#failedFuture(Throwable) + * @param supplier a function returning the value to be used to complete the returned Cffu + * @param the function's return type + * @return the new Cffu */ - @Contract(pure = true) - public Cffu failedFuture(Throwable ex) { - return create(CompletableFutureUtils.failedFuture(ex)); + @CheckReturnValue(explanation = "should use the returned Cffu; otherwise, prefer method `runAsync`") + public Cffu supplyAsync(Supplier supplier) { + return supplyAsync(supplier, defaultExecutor); } /** - * 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. + * Returns a new Cffu that is asynchronously completed by a task running + * in the given executor with the value obtained by calling the given Supplier. * - * @param ex the exception - * @param the type of the value - * @return the exceptionally completed CompletionStage - * @see CompletableFuture#failedStage(Throwable) - * @see CompletableFuture#minimalCompletionStage() + * @param supplier a function returning the value to be used to complete the returned Cffu + * @param executor the executor to use for asynchronous execution + * @param the function's return type + * @return the new Cffu */ - @Contract(pure = true) - public CompletionStage failedStage(Throwable ex) { - return createMin((CompletableFuture) CompletableFutureUtils.failedStage(ex)); + @CheckReturnValue(explanation = "should use the returned Cffu; otherwise, prefer method `runAsync`") + public Cffu supplyAsync(Supplier supplier, Executor executor) { + return create(CompletableFuture.supplyAsync(supplier, executor)); } - //////////////////////////////////////////////////////////////////////////////// - //# Factory Methods, equivalent to same name static methods of CompletableFuture - // - // create by logic/lambda - // - runAsync* - // - supplyAsync* - //////////////////////////////////////////////////////////////////////////////// - /** * 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); @@ -170,118 +142,78 @@ public Cffu runAsync(Runnable 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)); } - /** - * Returns a new Cffu that is asynchronously completed - * by a task running in the {@link #defaultExecutor()} with - * the value obtained by calling the given Supplier. - * - * @param supplier a function returning the value to be used to complete the returned Cffu - * @param the function's return type - * @return the new Cffu - * @see CompletableFuture#supplyAsync(Supplier) - */ - @CheckReturnValue(explanation = "should use the returned Cffu; otherwise, prefer method `runAsync`") - public Cffu supplyAsync(Supplier supplier) { - return supplyAsync(supplier, defaultExecutor); - } - - /** - * Returns a new Cffu that is asynchronously completed by a task running - * in the given executor with the value obtained by calling the given Supplier. - * - * @param supplier a function returning the value to be used to complete the returned Cffu - * @param executor the executor to use for asynchronous execution - * @param the function's return type - * @return the new Cffu - * @see CompletableFuture#supplyAsync(Supplier, Executor) - */ - @CheckReturnValue(explanation = "should use the returned Cffu; otherwise, prefer method `runAsync`") - public Cffu supplyAsync(Supplier supplier, Executor executor) { - return create(CompletableFuture.supplyAsync(supplier, executor)); - } - + // endregion //////////////////////////////////////////////////////////////////////////////// - //# Factory Methods - // - // - newIncompleteCffu: equivalent to CompletableFuture constructor - // - // - toCffu: CF/CompletionStage -> Cffu - // - toCffuArray: CF/CompletionStage[] -> Cffu[] + // region## allOf* Methods(including mostResultsOfSuccess) //////////////////////////////////////////////////////////////////////////////// /** - * 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} */ @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) */ @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, @@ -298,54 +230,24 @@ public final Cffu[] toCffuArray(CompletionStage... stages) { *

  • {@link #allResultsOf(CompletionStage[])} *
  • {@link #allTupleOf(CompletionStage, CompletionStage)} / * {@link #allTupleOf(CompletionStage, CompletionStage, CompletionStage, CompletionStage, CompletionStage)} - * (provided overloaded methods with 2~5 input) * *

    * If you need the successful results of given stages in the given time, prefer below methods: *

      *
    • {@link #mostResultsOfSuccess(Object, long, TimeUnit, CompletionStage[])} - *
    • {@link #mostTupleOfSuccess(long, TimeUnit, CompletionStage, CompletionStage)} - *
    • {@link #mostTupleOfSuccess(long, TimeUnit, CompletionStage, CompletionStage, CompletionStage, CompletionStage, CompletionStage)} + *
    • {@link #mostTupleOfSuccess(long, TimeUnit, CompletionStage, CompletionStage)} / + * {@link #mostTupleOfSuccess(long, TimeUnit, CompletionStage, CompletionStage, CompletionStage, CompletionStage, CompletionStage)} *
    * * @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 #allResultsOf(CompletionStage[]) - * @see #allTupleOf(CompletionStage, CompletionStage) - * @see #allTupleOf(CompletionStage, CompletionStage, CompletionStage, CompletionStage, CompletionStage) - * @see #mostResultsOfSuccess(Object, long, TimeUnit, CompletionStage[]) - * @see #mostTupleOfSuccess(long, TimeUnit, CompletionStage, CompletionStage) - * @see #mostTupleOfSuccess(long, TimeUnit, CompletionStage, CompletionStage, CompletionStage, CompletionStage, CompletionStage) - * @see CompletableFutureUtils#allOf(CompletionStage[]) */ @Contract(pure = true) 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 @@ -367,78 +269,44 @@ public final Cffu> allResultsOf(CompletionStage... cfs) * If you need the successful results of given stages in the given time, prefer below methods: *

      *
    • {@link #mostResultsOfSuccess(Object, long, TimeUnit, CompletionStage[])} - *
    • {@link #mostTupleOfSuccess(long, TimeUnit, CompletionStage, CompletionStage)} - *
    • {@link #mostTupleOfSuccess(long, TimeUnit, CompletionStage, CompletionStage, CompletionStage, CompletionStage, CompletionStage)} + *
    • {@link #mostTupleOfSuccess(long, TimeUnit, CompletionStage, CompletionStage)} / + * {@link #mostTupleOfSuccess(long, TimeUnit, CompletionStage, CompletionStage, CompletionStage, CompletionStage, CompletionStage)} *
    * * @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 #allResultsOfFastFail(CompletionStage[]) - * @see #allTupleOfFastFail(CompletionStage, CompletionStage) - * @see #allTupleOfFastFail(CompletionStage, CompletionStage, CompletionStage, CompletionStage, CompletionStage) - * @see #mostResultsOfSuccess(Object, long, TimeUnit, CompletionStage[]) - * @see #mostTupleOfSuccess(long, TimeUnit, CompletionStage, CompletionStage) - * @see #mostTupleOfSuccess(long, TimeUnit, CompletionStage, CompletionStage, CompletionStage, CompletionStage, CompletionStage) - * @see #allOf(CompletionStage[]) */ @Contract(pure = true) 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) - */ - @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, @@ -453,8 +321,6 @@ public final Cffu> mostResultsOfSuccess( * @return a new Cffu 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 @@ -462,50 +328,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 +352,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 +385,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 +419,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 +453,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 +546,119 @@ 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 + */ + @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 + */ + @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 + */ + @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 + */ + @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 +690,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 +702,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 +718,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 +728,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..1fe4cb25 100644 --- a/cffu-core/src/main/java/io/foldright/cffu/CompletableFutureUtils.java +++ b/cffu-core/src/main/java/io/foldright/cffu/CompletableFutureUtils.java @@ -22,140 +22,18 @@ /** - * 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 - // - // - mRun*Async(Runnable): Runnable* -> CompletableFuture - // mRunAsync / mRunFastFailAsync - // - mSupply*Async(Supplier): Supplier* -> CompletableFuture> - // mSupplyAsync / mSupplyFastFailAsync / mSupplyMostSuccessAsync + // region# CF Factory Methods(including static methods of CF) //////////////////////////////////////////////////////////////////////////////// - /** - * Returns a new CompletableFuture that is asynchronously completed - * by tasks running in the CompletableFuture's default asynchronous execution facility - * after runs the given actions. - * - * @param actions the actions to run before completing the returned CompletableFuture - * @return the new CompletableFuture - * @see #allOf(CompletionStage[]) - * @see CompletableFuture#runAsync(Runnable) - */ - public static CompletableFuture mRunAsync(Runnable... actions) { - return mRunAsync(AsyncPoolHolder.ASYNC_POOL, actions); - } - - /** - * Returns a new CompletableFuture that is asynchronously completed - * by tasks running in the given Executor after runs the given actions. - * - * @param executor the executor to use for asynchronous execution - * @param actions the actions to run before completing the returned CompletableFuture - * @return the new CompletableFuture - * @see #allOf(CompletionStage[]) - * @see CompletableFuture#runAsync(Runnable, Executor) - */ - public static CompletableFuture mRunAsync(Executor executor, Runnable... actions) { - requireNonNull(executor, "executor is null"); - requireArrayAndEleNonNull("action", actions); - - return CompletableFuture.allOf(wrapActions(executor, actions)); - } - - /** - * Returns a new CompletableFuture that is asynchronously completed - * by tasks running in the CompletableFuture's default asynchronous execution facility - * after runs the given actions. - *

    - * This method is the same as {@link #mRunAsync(Runnable...)} except for the fast-fail behavior. - * - * @param actions the actions to run before completing the returned CompletableFuture - * @return the new CompletableFuture - * @see #allOfFastFail(CompletionStage[]) - * @see CompletableFuture#runAsync(Runnable) - */ - public static CompletableFuture mRunFastFailAsync(Runnable... actions) { - return mRunFastFailAsync(AsyncPoolHolder.ASYNC_POOL, actions); - } - - /** - * Returns a new CompletableFuture that is asynchronously completed - * by tasks running in the given Executor after runs the given actions. - *

    - * This method is the same as {@link #mRunAsync(Executor, Runnable...)} except for the fast-fail behavior. - * - * @param executor the executor to use for asynchronous execution - * @param actions the actions to run before completing the returned CompletableFuture - * @return the new CompletableFuture - * @see #allOfFastFail(CompletionStage[]) - * @see CompletableFuture#runAsync(Runnable, Executor) - */ - public static CompletableFuture mRunFastFailAsync(Executor executor, Runnable... actions) { - requireNonNull(executor, "executor is null"); - requireArrayAndEleNonNull("action", actions); - - 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]; - for (int i = 0; i < actions.length; i++) { - cfs[i] = CompletableFuture.runAsync(actions[i], executor); - } - 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); - } - - /** - * 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)); - } + //////////////////////////////////////////////////////////// + // region## Multi-Actions(M*) Methods(create by actions) + //////////////////////////////////////////////////////////// /** * Returns a new CompletableFuture that is asynchronously completed @@ -254,6 +132,52 @@ public static CompletableFuture> mSupplyMostSuccessAsync( 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") @@ -264,161 +188,86 @@ private static CompletableFuture[] wrapSuppliers( return cfs; } - //////////////////////////////////////////////////////////////////////////////// - //# 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, - * with a CompletionException holding this exception as its cause. - * Otherwise, the results, if any, of the given stages are not reflected in the returned - * CompletableFuture({@code CompletableFuture}), but may be obtained by inspecting them individually. - * If no stages are provided, returns a CompletableFuture completed with the value {@code null}. - *

    - * This method is the same as {@link CompletableFuture#allOf(CompletableFuture[])}, - * except that the parameter type is more generic {@link CompletionStage} instead of {@link CompletableFuture}. - *

    - * If you need the results of given stages, prefer below methods: - *

      - *
    • {@link #allResultsOf(CompletionStage[])} - *
    • {@link #allTupleOf(CompletionStage, CompletionStage)} / - * {@link #allTupleOf(CompletionStage, CompletionStage, CompletionStage, CompletionStage, CompletionStage)} - * (provided overloaded methods with 2~5 input) - *
    - *

    - * If you need the successful results of given stages in the given time, prefer below methods: - *

      - *
    • {@link #mostResultsOfSuccess(Object, long, TimeUnit, CompletionStage[])} - *
    • {@link #mostResultsOfSuccess(Object, Executor, long, TimeUnit, CompletionStage[])} - *
    • {@link #mostTupleOfSuccess(long, TimeUnit, CompletionStage, CompletionStage)} - *
    • {@link #mostTupleOfSuccess(Executor, long, TimeUnit, CompletionStage, CompletionStage)} - *
    • {@link #mostTupleOfSuccess(long, TimeUnit, CompletionStage, CompletionStage, CompletionStage, CompletionStage, CompletionStage)} - *
    • {@link #mostTupleOfSuccess(Executor, long, TimeUnit, CompletionStage, CompletionStage, CompletionStage, CompletionStage, CompletionStage)} - *
    + * Returns a new CompletableFuture that is asynchronously completed + * by tasks running in the CompletableFuture's default asynchronous execution facility + * after runs the given actions. * - * @param 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 #allResultsOf(CompletionStage[]) - * @see #allTupleOf(CompletionStage, CompletionStage) - * @see #allTupleOf(CompletionStage, CompletionStage, CompletionStage, CompletionStage, CompletionStage) - * @see #mostResultsOfSuccess(Object, long, TimeUnit, CompletionStage[]) - * @see #mostResultsOfSuccess(Object, Executor, long, TimeUnit, CompletionStage[]) - * @see #mostTupleOfSuccess(long, TimeUnit, CompletionStage, CompletionStage) - * @see #mostTupleOfSuccess(Executor, long, TimeUnit, CompletionStage, CompletionStage) - * @see #mostTupleOfSuccess(long, TimeUnit, CompletionStage, CompletionStage, CompletionStage, CompletionStage, CompletionStage) - * @see #mostTupleOfSuccess(Executor, long, TimeUnit, CompletionStage, CompletionStage, CompletionStage, CompletionStage, CompletionStage) - * @see CompletableFuture#allOf(CompletableFuture[]) + * @param actions the actions to run before completing the returned CompletableFuture + * @return the new CompletableFuture + * @see #allOf(CompletionStage[]) + * @see CompletableFuture#runAsync(Runnable) */ - public static CompletableFuture allOf(CompletionStage... cfs) { - requireNonNull(cfs, "cfs is null"); - if (cfs.length == 0) return completedFuture(null); - // 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 (cfs.length == 1) return toNonMinCfCopy(requireNonNull(cfs[0], "cf1 is null")).thenApply(unused -> null); - return CompletableFuture.allOf(f_toCfArray(cfs)); + public static CompletableFuture mRunAsync(Runnable... actions) { + return mRunAsync(AsyncPoolHolder.ASYNC_POOL, actions); } /** - * 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. + * Returns a new CompletableFuture that is asynchronously completed + * by tasks running in the given Executor after runs the given actions. * - * @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[]) + * @param executor the executor to use for asynchronous execution + * @param actions the actions to run before completing the returned CompletableFuture + * @return the new CompletableFuture * @see #allOf(CompletionStage[]) + * @see CompletableFuture#runAsync(Runnable, Executor) */ - @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); + public static CompletableFuture mRunAsync(Executor executor, Runnable... actions) { + requireNonNull(executor, "executor is null"); + requireArrayAndEleNonNull("action", actions); - CompletableFuture> ret = CompletableFuture.allOf(resultSetterCfs) - .thenApply(unused -> arrayList(result)); - return f_cast(ret); + return CompletableFuture.allOf(wrapActions(executor, actions)); } /** - * 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 - * *without* waiting other incomplete given stages, with a CompletionException holding this exception as its cause. - * Otherwise, the results, if any, of the given stages are not reflected - * in the returned CompletableFuture({@code CompletableFuture}), - * but may be obtained by inspecting them individually. - * If no stages are provided, returns a CompletableFuture completed with the value {@code null}. - *

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

    - * If you need the results of given stages, prefer below methods: - *

      - *
    • {@link #allResultsOfFastFail(CompletionStage[])} - *
    • {@link #allTupleOfFastFail(CompletionStage, CompletionStage)} / - * {@link #allTupleOfFastFail(CompletionStage, CompletionStage, CompletionStage, CompletionStage, CompletionStage)} - * (provided overloaded methods with 2~5 input) - *
    + * Returns a new CompletableFuture that is asynchronously completed + * by tasks running in the CompletableFuture's default asynchronous execution facility + * after runs the given actions. *

    - * If you need the successful results of given stages in the given time, prefer below methods: - *

      - *
    • {@link #mostResultsOfSuccess(Object, long, TimeUnit, CompletionStage[])} - *
    • {@link #mostResultsOfSuccess(Object, Executor, long, TimeUnit, CompletionStage[])} - *
    • {@link #mostTupleOfSuccess(long, TimeUnit, CompletionStage, CompletionStage)} - *
    • {@link #mostTupleOfSuccess(Executor, long, TimeUnit, CompletionStage, CompletionStage)} - *
    • {@link #mostTupleOfSuccess(long, TimeUnit, CompletionStage, CompletionStage, CompletionStage, CompletionStage, CompletionStage)} - *
    • {@link #mostTupleOfSuccess(Executor, long, TimeUnit, CompletionStage, CompletionStage, CompletionStage, CompletionStage, CompletionStage)} - *
    + * This method is the same as {@link #mRunAsync(Runnable...)} except for the fast-fail behavior. * - * @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 #allResultsOfFastFail(CompletionStage[]) - * @see #allTupleOfFastFail(CompletionStage, CompletionStage) - * @see #allTupleOfFastFail(CompletionStage, CompletionStage, CompletionStage, CompletionStage, CompletionStage) - * @see #mostResultsOfSuccess(Object, long, TimeUnit, CompletionStage[]) - * @see #mostResultsOfSuccess(Object, Executor, long, TimeUnit, CompletionStage[]) - * @see #mostTupleOfSuccess(long, TimeUnit, CompletionStage, CompletionStage) - * @see #mostTupleOfSuccess(Executor, long, TimeUnit, CompletionStage, CompletionStage) - * @see #mostTupleOfSuccess(long, TimeUnit, CompletionStage, CompletionStage, CompletionStage, CompletionStage, CompletionStage) - * @see #mostTupleOfSuccess(Executor, long, TimeUnit, CompletionStage, CompletionStage, CompletionStage, CompletionStage, CompletionStage) - * @see #allOf(CompletionStage[]) + * @param actions the actions to run before completing the returned CompletableFuture + * @return the new CompletableFuture + * @see #allOfFastFail(CompletionStage[]) + * @see CompletableFuture#runAsync(Runnable) */ - @Contract(pure = true) - public static CompletableFuture allOfFastFail(CompletionStage... cfs) { - requireCfsAndEleNonNull(cfs); - final int len = cfs.length; - if (len == 0) return completedFuture(null); - // Defensive copy input cf to non-minimal-stage instance 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(unused -> null); + public static CompletableFuture mRunFastFailAsync(Runnable... actions) { + return mRunFastFailAsync(AsyncPoolHolder.ASYNC_POOL, actions); + } - 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); + /** + * Returns a new CompletableFuture that is asynchronously completed + * by tasks running in the given Executor after runs the given actions. + *

    + * This method is the same as {@link #mRunAsync(Executor, Runnable...)} except for the fast-fail behavior. + * + * @param executor the executor to use for asynchronous execution + * @param actions the actions to run before completing the returned CompletableFuture + * @return the new CompletableFuture + * @see #allOfFastFail(CompletionStage[]) + * @see CompletableFuture#runAsync(Runnable, Executor) + */ + public static CompletableFuture mRunFastFailAsync(Executor executor, Runnable... actions) { + requireNonNull(executor, "executor is null"); + requireArrayAndEleNonNull("action", actions); - // NOTE: fill the ONE MORE element of failedOrBeIncomplete HERE: - // a cf that is successful when all given cfs success, otherwise be incomplete - failedOrBeIncomplete[len] = CompletableFuture.allOf(successOrBeIncomplete); + return allOfFastFail(wrapActions(executor, actions)); + } - CompletableFuture ret = CompletableFuture.anyOf(failedOrBeIncomplete); - return f_cast(ret); + private static CompletableFuture[] wrapActions(Executor executor, Runnable[] actions) { + @SuppressWarnings("unchecked") + CompletableFuture[] cfs = new CompletableFuture[actions.length]; + for (int i = 0; i < actions.length; i++) { + cfs[i] = CompletableFuture.runAsync(actions[i], executor); + } + return cfs; } + // endregion + //////////////////////////////////////////////////////////// + // region## allOf* Methods(including mostResultsOfSuccess) + //////////////////////////////////////////////////////////// + /** * 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; @@ -427,16 +276,10 @@ public static CompletableFuture allOfFastFail(CompletionStage... cfs) { * 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 @@ -535,6 +378,128 @@ private static T[] MGetSuccessNow0(@Nullable Object valueIfNotSuccess, Compl return (T[]) ret; } + /** + * 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} + */ + @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 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. + * Otherwise, the results, if any, of the given stages are not reflected in the returned + * CompletableFuture({@code CompletableFuture}), but may be obtained by inspecting them individually. + * If no stages are provided, returns a CompletableFuture completed with the value {@code null}. + *

    + * This method is the same as {@link CompletableFuture#allOf(CompletableFuture[])}, + * except that the parameter type is more generic {@link CompletionStage} instead of {@link CompletableFuture}. + *

    + * If you need the results of given stages, prefer below methods: + *

      + *
    • {@link #allResultsOf(CompletionStage[])} + *
    • {@link #allTupleOf(CompletionStage, CompletionStage)} / + * {@link #allTupleOf(CompletionStage, CompletionStage, CompletionStage, CompletionStage, CompletionStage)} + *
    + *

    + * If you need the successful results of given stages in the given time, prefer below methods: + *

      + *
    • {@link #mostResultsOfSuccess(Object, long, TimeUnit, CompletionStage[])} + *
    • {@link #mostTupleOfSuccess(long, TimeUnit, CompletionStage, CompletionStage)} / + * {@link #mostTupleOfSuccess(long, TimeUnit, CompletionStage, CompletionStage, CompletionStage, CompletionStage, CompletionStage)} + *
    + * + * @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} + */ + public static CompletableFuture allOf(CompletionStage... cfs) { + requireNonNull(cfs, "cfs is null"); + if (cfs.length == 0) return completedFuture(null); + // 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 (cfs.length == 1) return toNonMinCfCopy(requireNonNull(cfs[0], "cf1 is null")).thenApply(unused -> null); + return CompletableFuture.allOf(f_toCfArray(cfs)); + } + + /** + * 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 + * *without* waiting other incomplete given stages, with a CompletionException holding this exception as its cause. + * Otherwise, the results, if any, of the given stages are not reflected + * in the returned CompletableFuture({@code CompletableFuture}), + * but may be obtained by inspecting them individually. + * If no stages are provided, returns a CompletableFuture completed with the value {@code null}. + *

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

    + * If you need the results of given stages, prefer below methods: + *

      + *
    • {@link #allResultsOfFastFail(CompletionStage[])} + *
    • {@link #allTupleOfFastFail(CompletionStage, CompletionStage)} / + * {@link #allTupleOfFastFail(CompletionStage, CompletionStage, CompletionStage, CompletionStage, CompletionStage)} + * (provided overloaded methods with 2~5 input) + *
    + *

    + * If you need the successful results of given stages in the given time, prefer below methods: + *

      + *
    • {@link #mostResultsOfSuccess(Object, long, TimeUnit, CompletionStage[])} + *
    • {@link #mostTupleOfSuccess(long, TimeUnit, CompletionStage, CompletionStage)} / + * {@link #mostTupleOfSuccess(long, TimeUnit, CompletionStage, CompletionStage, CompletionStage, CompletionStage, CompletionStage)} + *
    + * + * @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} + */ + @Contract(pure = true) + public static CompletableFuture allOfFastFail(CompletionStage... cfs) { + requireCfsAndEleNonNull(cfs); + final int len = cfs.length; + if (len == 0) return completedFuture(null); + // Defensive copy input cf to non-minimal-stage instance 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(unused -> null); + + 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] = CompletableFuture.allOf(successOrBeIncomplete); + + CompletableFuture ret = CompletableFuture.anyOf(failedOrBeIncomplete); + return f_cast(ret); + } + @SafeVarargs private static > S[] requireCfsAndEleNonNull(S... css) { return requireArrayAndEleNonNull("cf", css); @@ -647,48 +612,19 @@ private static CompletableFuture toNonMinCf(CompletionStage * e.g. {@code minimalCompletionStage().copy()}, {@code completedStage().copy()}. */ private static CompletableFuture toNonMinCfCopy(CompletionStage s) { - final CompletableFuture f = toCf(s); - return isMinStageCf(f) ? f.toCompletableFuture() : copy(f); - } - - 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); + final CompletableFuture f = toCf(s); + return isMinStageCf(f) ? f.toCompletableFuture() : copy(f); + } + + private static boolean isMinStageCf(CompletableFuture cf) { + return "java.util.concurrent.CompletableFuture$MinimalStage".equals(cf.getClass().getName()); } + // endregion + //////////////////////////////////////////////////////////// + // region## anyOf* Methods + //////////////////////////////////////////////////////////// + /** * Returns a new CompletableFuture that is successful when any of the given stages success, * with the same result. Otherwise, all the given stages complete exceptionally, @@ -703,7 +639,6 @@ public static CompletableFuture anyOf(CompletionStage... cfs * @param cfs the stages * @return a new CompletableFuture 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[]) */ @Contract(pure = true) @SafeVarargs @@ -729,25 +664,40 @@ 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[]) */ @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 +717,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 +750,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 +784,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 +818,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 +1026,125 @@ 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); - } - - /** - * Returns a new CompletableFuture that, when the given stage completes normally, - * executes the given actions using the given Executor. - * - * @param actions the actions to perform before completing the returned CompletableFuture - * @return the new 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))); - } - - /** - * 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 #thenMRunAsync(CompletionStage, 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, Runnable... actions) { - return thenMRunFastFailAsync(cf, AsyncPoolHolder.ASYNC_POOL, actions); - } - - /** - * 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 #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); - } + // endregion + //////////////////////////////////////////////////////////// + // region## Immediate Value Argument Factory Methods(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. + * 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 */ - @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 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, - * is executed using the CompletableFuture's default asynchronous execution facility, - * with the given stage's result as the argument to the given actions. + * 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 #thenMAcceptAsync(CompletionStage, Consumer[])} - * 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 */ - @SafeVarargs - public static CompletableFuture thenMAcceptFastFailAsync( - CompletionStage cf, Consumer... actions) { - return thenMAcceptFastFailAsync(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, - * is executed using the given Executor, with the given stage's result as the argument to the given actions. + * 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 #thenMAcceptAsync(CompletionStage, Executor, Consumer[])} - * 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 ex the exception + * @param the type of the value + * @return the exceptionally completed CompletionStage */ - @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); + @Contract(pure = true) + public static CompletionStage failedStage(Throwable ex) { + if (IS_JAVA9_PLUS) { + return CompletableFuture.failedStage(ex); } - return cfs; + 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 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. + // endregion + //////////////////////////////////////////////////////////// + // region## Delay Execution(backport methods) + //////////////////////////////////////////////////////////// + + /** + * 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 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 + * @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) { + return delayedExecutor(delay, unit, AsyncPoolHolder.ASYNC_POOL); } /** - * 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 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, Executor executor, Function... fns) { - requireNonNull(cf, "cf is null"); + @Contract(pure = true) + public static Executor delayedExecutor(long delay, TimeUnit unit, Executor executor) { + requireNonNull(unit, "unit is null"); requireNonNull(executor, "executor is null"); - requireArrayAndEleNonNull("fn", fns); + if (IS_JAVA9_PLUS) { + return CompletableFuture.delayedExecutor(delay, unit, executor); + } + return new DelayedExecutor(delay, unit, executor); + } - return toNonMinCf(cf).thenCompose(v -> allResultsOf(wrapFunctions(executor, v, fns))); + /** + * 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). + */ + @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 + //////////////////////////////////////////////////////////// + /** * Returns a new CompletableFuture that, when the given stage completes normally, * is executed using the CompletableFuture's default asynchronous execution facility, @@ -1345,6 +1244,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 +1292,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) - */ - @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"); + * @see CompletableFuture#thenRunAsync(Runnable, Executor) + * @see #allOf(CompletionStage[]) + */ + 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. @@ -1516,7 +1458,6 @@ public static CompletableFuture thenAcceptBothFastFailAsync( * * @param fn the function to use to compute the value of the returned CompletableFuture * @return the new CompletableFuture - * @see CompletionStage#thenCombine(CompletionStage, BiFunction) */ @SuppressWarnings("unchecked") public static CompletableFuture thenCombineFastFail( @@ -1544,7 +1485,6 @@ public static CompletableFuture thenCombineFastFail( * * @param fn the function to use to compute the value of the returned CompletableFuture * @return the new CompletableFuture - * @see CompletionStage#thenCombineAsync(CompletionStage, BiFunction) */ public static CompletableFuture thenCombineFastFailAsync( CompletionStage cf1, CompletionStage cf2, @@ -1565,7 +1505,6 @@ public static CompletableFuture thenCombineFastFailAsync( * * @param fn the function to use to compute the value of the returned CompletableFuture * @return the new CompletableFuture - * @see CompletionStage#thenCombineAsync(CompletionStage, BiFunction, Executor) */ @SuppressWarnings("unchecked") public static CompletableFuture thenCombineFastFailAsync( @@ -1582,135 +1521,149 @@ 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) */ - 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) */ - 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) */ - 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) */ - 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) */ - 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) */ - 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. @@ -1721,7 +1674,6 @@ public static CompletableFuture acceptEitherSuccessAsync( * @param fn the function to use to compute the value of the returned CompletableFuture * @param the function's return type * @return the new CompletableFuture - * @see CompletionStage#applyToEither(CompletionStage, Function) */ public static CompletableFuture applyToEitherSuccess( CompletionStage cf1, CompletionStage cf2, Function fn) { @@ -1742,7 +1694,6 @@ public static CompletableFuture applyToEitherSuccess( * @param fn the function to use to compute the value of the returned CompletableFuture * @param the function's return type * @return the new CompletableFuture - * @see CompletionStage#applyToEitherAsync(CompletionStage, Function) */ public static CompletableFuture applyToEitherSuccessAsync( CompletionStage cf1, CompletionStage cf2, Function fn) { @@ -1760,7 +1711,6 @@ public static CompletableFuture applyToEitherSuccessAsync( * @param executor the executor to use for asynchronous execution * @param the function's return type * @return the new CompletableFuture - * @see CompletionStage#applyToEitherAsync(CompletionStage, Function, Executor) */ public static CompletableFuture applyToEitherSuccessAsync( CompletionStage cf1, CompletionStage cf2, @@ -1772,201 +1722,125 @@ 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 + */ + 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 */ - @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 */ - @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 */ - @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 */ - @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 */ - @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 +1882,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} @@ -2018,7 +1895,7 @@ C exceptionallyAsync(C cf, Function fn, Executor executo * * @param timeout how long to wait before completing exceptionally with a TimeoutException, in units of {@code unit} * @param unit a {@code TimeUnit} determining how to interpret the {@code timeout} parameter - * @return a new CompletableFuture + * @return the new CompletableFuture * @see #cffuOrTimeout(CompletableFuture, Executor, long, TimeUnit) */ public static > C cffuOrTimeout(C cf, long timeout, TimeUnit unit) { @@ -2032,7 +1909,7 @@ public static > C cffuOrTimeout(C cf, long timeou * @param executorWhenTimeout the async executor when triggered by timeout * @param timeout how long to wait before completing exceptionally with a TimeoutException, in units of {@code unit} * @param unit a {@code TimeUnit} determining how to interpret the {@code timeout} parameter - * @return a new CompletableFuture + * @return the new CompletableFuture */ public static > C cffuOrTimeout( C cf, Executor executorWhenTimeout, long timeout, TimeUnit unit) { @@ -2092,7 +1969,7 @@ public static > C orTimeout(C cf, long timeout, T * @param value the value to use upon timeout * @param timeout how long to wait before completing normally with the given value, in units of {@code unit} * @param unit a {@code TimeUnit} determining how to interpret the {@code timeout} parameter - * @return a new CompletableFuture + * @return the new CompletableFuture * @see #cffuCompleteOnTimeout(CompletableFuture, Object, Executor, long, TimeUnit) */ public static > @@ -2107,7 +1984,7 @@ C cffuCompleteOnTimeout(C cf, @Nullable T value, long timeout, TimeUnit unit) { * @param executorWhenTimeout the async executor when triggered by timeout * @param timeout how long to wait before completing normally with the given value, in units of {@code unit} * @param unit a {@code TimeUnit} determining how to interpret the {@code timeout} parameter - * @return a new CompletableFuture + * @return the new CompletableFuture */ public static > C cffuCompleteOnTimeout(C cf, @Nullable T value, Executor executorWhenTimeout, long timeout, TimeUnit unit) { @@ -2187,7 +2064,14 @@ private static void completeCf(CompletableFuture cf, Object value, @Null } } - //# Advanced methods of CompletionStage + // endregion + //////////////////////////////////////////////////////////// + // region## Advanced Methods of CompletionStage(compose* and handle-like methods) + // + // NOTE about advanced meaning: + // - `compose` methods, input function argument return CompletionStage + // - handle successful and failed result together(handle*/whenComplete*/peek*) + //////////////////////////////////////////////////////////// /** * Returns a new CompletableFuture that, when given CompletableFuture completes exceptionally, @@ -2247,7 +2131,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, @@ -2319,6 +2295,9 @@ public static T getSuccessNow(CompletableFuture cf, @Nullable T * .map(Future::resultNow) * .toList(); * } + * + * @return the computed result + * @throws IllegalStateException if the task has not completed or the task did not complete with a result */ @Contract(pure = true) @Nullable @@ -2367,7 +2346,6 @@ public static T resultNow(Future cf) { * @return the exception thrown by the task * @throws IllegalStateException if the task has not completed, the task completed normally, * or the task was cancelled - * @see CompletableFuture#resultNow() */ @Contract(pure = true) public static Throwable exceptionNow(Future cf) { @@ -2404,9 +2382,6 @@ public static Throwable exceptionNow(Future cf) { * * @return the computation state * @see Future#state() - * @see CompletableFuture#state() - * @see CffuState - * @see Future.State */ @Contract(pure = true) public static CffuState state(Future cf) { @@ -2447,7 +2422,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 @@ -2455,6 +2433,7 @@ public static CffuState state(Future cf) { * * @param supplier a function returning the value to be used to complete given CompletableFuture * @return the given CompletableFuture + * @see CompletableFuture#completeAsync(Supplier) */ public static > C completeAsync(C cf, Supplier supplier) { return completeAsync(cf, supplier, AsyncPoolHolder.ASYNC_POOL); @@ -2467,6 +2446,7 @@ public static > C completeAsync(C cf, * @param supplier a function returning the value to be used to complete given CompletableFuture * @param executor the executor to use for asynchronous execution * @return the given CompletableFuture + * @see CompletableFuture#completeAsync(Supplier, Executor) */ public static > C completeAsync(C cf, Supplier supplier, Executor executor) { @@ -2517,7 +2497,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 @@ -2530,6 +2513,7 @@ C completeExceptionallyAsync(C cf, Supplier supplier, Execu * if run on old Java 8, just return a *normal* CompletableFuture which is NOT with a *minimal* CompletionStage. * * @return the new CompletionStage + * @see CompletableFuture#minimalCompletionStage() */ @Contract(pure = true) public static CompletionStage minimalCompletionStage(CompletableFuture cf) { @@ -2548,6 +2532,7 @@ public static CompletionStage minimalCompletionStage(CompletableFuture * from completing, while still being able to arrange dependent actions. * * @return the new CompletableFuture + * @see CompletableFuture#copy() */ @Contract(pure = true) public static CompletableFuture copy(CompletableFuture cf) { @@ -2562,7 +2547,8 @@ public static CompletableFuture copy(CompletableFuture cf) { * Returns a new incomplete CompletableFuture of the type to be returned by a CompletionStage method. * * @param the type of the value - * @return a new CompletableFuture + * @return the new CompletableFuture + * @see CompletableFuture#newIncompleteFuture() */ @Contract(pure = true) public static CompletableFuture newIncompleteFuture(CompletableFuture cf) { @@ -2573,23 +2559,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 +2602,9 @@ public static CompletableFuture[] completableFutureListToArray(List Collection>.toCffu(cffuFactory: CffuFactory): List Array>.toCffu(cffuFactory: CffuFactory): Array> = cffuFactory.toCffuArray(*this) -//////////////////////////////////////// -//# allOf*/mostResultsOfSuccess* methods for Array/Collection -// -// - allResultsOfCffu -// - allOfCffu -// - allResultsOfFastFailCffu -// - allOfFastFailCffu -//////////////////////////////////////// +// endregion +//////////////////////////////////////////////////////////////////////////////// +// region# allOf* Methods for Collection/Array(including mostResultsOfSuccess) +//////////////////////////////////////////////////////////////////////////////// /** * Placeholder for optional [CffuFactory] argument. @@ -65,6 +61,171 @@ private val ABSENT: CffuFactory = CffuFactory.builder { }.build() private const val ERROR_MSG_FOR_COLL = "no cffuFactory argument provided when this collection is empty" private const val ERROR_MSG_FOR_ARRAY = "no cffuFactory argument provided when this array is empty" +/** + * Returns a new Cffu with the results in the **same order** of the given Cffus arguments, + * the new Cffu success when all the given Cffus success. + * If any of the given Cffus complete exceptionally, then the returned Cffu + * also does so *without* waiting other incomplete given Cffus, + * with a CompletionException holding this exception as its cause. + * If no Cffus are provided, returns a Cffu completed with the value empty list. + * + * This method is the same as [allOfFastFailCffu], except the returned Cffu contains the results of input Cffus. + * + * This method is the same as [CffuFactory.allResultsOfFastFail], providing this method is convenient for method chaining. + * + * If this collection is not empty, `cffuFactory` argument is optional, use the `cffuFactory` of the first cffu element. + * If this collection is empty and no`cffuFactory` provided, throw [IllegalArgumentException]. + * + * @see allOfFastFailCffu + * @see CffuFactory.allResultsOfFastFail + */ +fun Collection>.allResultsOfFastFailCffu(cffuFactory: CffuFactory = ABSENT): Cffu> { + val factory: CffuFactory = if (cffuFactory !== ABSENT) cffuFactory + else firstOrNull()?.cffuFactory() ?: throw IllegalArgumentException(ERROR_MSG_FOR_COLL) + return factory.allResultsOfFastFail(*toTypedArray()) +} + +/** + * Returns a new Cffu with the results in the **same order** of the given Cffus arguments, + * the new Cffu success when all the given Cffus success. + * If any of the given Cffus complete exceptionally, then the returned Cffu + * also does so *without* waiting other incomplete given Cffus, + * with a CompletionException holding this exception as its cause. + * If no Cffus are provided, returns a Cffu completed with the value empty list. + * + * This method is the same as [allOfFastFailCffu], except the returned Cffu contains the results of input Cffus. + * + * This method is the same as [CffuFactory.allResultsOfFastFail], providing this method is convenient for method chaining. + * + * If this array is not empty, `cffuFactory` argument is optional, use the `cffuFactory` of the first cffu element. + * If this array is empty and no`cffuFactory` provided, throw [IllegalArgumentException]. + * + * @see allOfFastFailCffu + * @see CffuFactory.allResultsOfFastFail + */ +fun Array>.allResultsOfFastFailCffu(cffuFactory: CffuFactory = ABSENT): Cffu> { + val factory: CffuFactory = if (cffuFactory !== ABSENT) cffuFactory + else firstOrNull()?.cffuFactory() ?: throw IllegalArgumentException(ERROR_MSG_FOR_ARRAY) + return factory.allResultsOfFastFail(*this) +} + +/** + * Returns a new Cffu with the results in the **same order** of the given stages arguments, + * the new Cffu success 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 [allOfFastFailCffu], except the returned Cffu contains the results of input Cffus. + * + * This method is the same as [CffuFactory.allResultsOfFastFail], providing this method is convenient for method chaining. + * + * @see allOfFastFailCffu + * @see CffuFactory.allResultsOfFastFail + */ +@JvmName("allResultsOfFastFailCffuCs") +fun Collection>.allResultsOfFastFailCffu(cffuFactory: CffuFactory): Cffu> = + cffuFactory.allResultsOfFastFail(*toTypedArray()) + +/** + * Returns a new Cffu with the results in the **same order** of the given stages arguments, + * the new Cffu success 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 [allOfFastFailCffu], except the returned Cffu contains the results of input Cffus. + * + * This method is the same as [CffuFactory.allResultsOfFastFail], providing this method is convenient for method chaining. + * + * @see allOfFastFailCffu + * @see CffuFactory.allResultsOfFastFail + */ +fun Array>.allResultsOfFastFailCffu(cffuFactory: CffuFactory): Cffu> = + cffuFactory.allResultsOfFastFail(*this) + +/** + * Returns a new Cffu with the most results in the **same order** of + * the given Cffus arguments in the given time(`timeout`, aka as many results as possible in the given time). + * + * If the given Cffu is successful, its result is the completed value; Otherwise the given valueIfNotSuccess. + * + * @param timeout how long to wait in units of `unit` + * @param unit a `TimeUnit` determining how to interpret the `timeout` parameter + * @param valueIfNotSuccess the value to return if not completed successfully + * @see CffuFactory.mostResultsOfSuccess + * @see CffuFactory.mostTupleOfSuccess + * @see Cffu.getSuccessNow + */ +fun Collection>.mostResultsOfSuccessCffu( + valueIfNotSuccess: T, timeout: Long, unit: TimeUnit, cffuFactory: CffuFactory = ABSENT +): Cffu> { + val factory: CffuFactory = if (cffuFactory !== ABSENT) cffuFactory + else firstOrNull()?.cffuFactory() ?: throw IllegalArgumentException(ERROR_MSG_FOR_COLL) + return factory.mostResultsOfSuccess(valueIfNotSuccess, timeout, unit, *toTypedArray()) +} + +/** + * Returns a new Cffu with the most results in the **same order** of + * the given Cffus arguments in the given time(`timeout`, aka as many results as possible in the given time). + * + * If the given Cffu is successful, its result is the completed value; Otherwise the given valueIfNotSuccess. + * + * @param timeout how long to wait in units of `unit` + * @param unit a `TimeUnit` determining how to interpret the `timeout` parameter + * @param valueIfNotSuccess the value to return if not completed successfully + * @see CffuFactory.mostResultsOfSuccess + * @see CffuFactory.mostTupleOfSuccess + * @see Cffu.getSuccessNow + */ +fun Array>.mostResultsOfSuccessCffu( + valueIfNotSuccess: T, timeout: Long, unit: TimeUnit, cffuFactory: CffuFactory = ABSENT +): Cffu> { + val factory: CffuFactory = if (cffuFactory !== ABSENT) cffuFactory + else firstOrNull()?.cffuFactory() ?: throw IllegalArgumentException(ERROR_MSG_FOR_ARRAY) + return factory.mostResultsOfSuccess(valueIfNotSuccess, timeout, unit, *this) +} + +/** + * Returns a new Cffu with the most results in the **same order** of + * the given stages arguments in the given time(`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 timeout how long to wait in units of `unit` + * @param unit a `TimeUnit` determining how to interpret the `timeout` parameter + * @param valueIfNotSuccess the value to return if not completed successfully + * @see CffuFactory.mostResultsOfSuccess + * @see CffuFactory.mostTupleOfSuccess + * @see Cffu.getSuccessNow + */ +@JvmName("mostResultsOfSuccessCffuCs") +fun Collection>.mostResultsOfSuccessCffu( + valueIfNotSuccess: T, timeout: Long, unit: TimeUnit, cffuFactory: CffuFactory +): Cffu> = + cffuFactory.mostResultsOfSuccess(valueIfNotSuccess, timeout, unit, *toTypedArray()) + +/** + * Returns a new Cffu with the most results in the **same order** of + * the given stages arguments in the given time(`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. + * (aka the result extraction logic is [Cffu.getSuccessNow]). + * + * @param timeout how long to wait in units of `unit` + * @param unit a `TimeUnit` determining how to interpret the `timeout` parameter + * @param valueIfNotSuccess the value to return if not completed successfully + * @see CffuFactory.mostResultsOfSuccess + * @see CffuFactory.mostTupleOfSuccess + * @see Cffu.getSuccessNow + */ +fun Array>.mostResultsOfSuccessCffu( + valueIfNotSuccess: T, timeout: Long, unit: TimeUnit, cffuFactory: CffuFactory +): Cffu> = + cffuFactory.mostResultsOfSuccess(valueIfNotSuccess, timeout, unit, *this) + /** * Returns a new Cffu with the results in the **same order** of the given Cffus arguments, * the new Cffu is completed when all the given Cffus complete. @@ -224,91 +385,6 @@ fun Collection>.allOfCffu(cffuFactory: CffuFactory): Cffu>.allOfCffu(cffuFactory: CffuFactory): Cffu = cffuFactory.allOf(*this) -/** - * Returns a new Cffu with the results in the **same order** of the given Cffus arguments, - * the new Cffu success when all the given Cffus success. - * If any of the given Cffus complete exceptionally, then the returned Cffu - * also does so *without* waiting other incomplete given Cffus, - * with a CompletionException holding this exception as its cause. - * If no Cffus are provided, returns a Cffu completed with the value empty list. - * - * This method is the same as [allOfFastFailCffu], except the returned Cffu contains the results of input Cffus. - * - * This method is the same as [CffuFactory.allResultsOfFastFail], providing this method is convenient for method chaining. - * - * If this collection is not empty, `cffuFactory` argument is optional, use the `cffuFactory` of the first cffu element. - * If this collection is empty and no`cffuFactory` provided, throw [IllegalArgumentException]. - * - * @see allOfFastFailCffu - * @see CffuFactory.allResultsOfFastFail - */ -fun Collection>.allResultsOfFastFailCffu(cffuFactory: CffuFactory = ABSENT): Cffu> { - val factory: CffuFactory = if (cffuFactory !== ABSENT) cffuFactory - else firstOrNull()?.cffuFactory() ?: throw IllegalArgumentException(ERROR_MSG_FOR_COLL) - return factory.allResultsOfFastFail(*toTypedArray()) -} - -/** - * Returns a new Cffu with the results in the **same order** of the given Cffus arguments, - * the new Cffu success when all the given Cffus success. - * If any of the given Cffus complete exceptionally, then the returned Cffu - * also does so *without* waiting other incomplete given Cffus, - * with a CompletionException holding this exception as its cause. - * If no Cffus are provided, returns a Cffu completed with the value empty list. - * - * This method is the same as [allOfFastFailCffu], except the returned Cffu contains the results of input Cffus. - * - * This method is the same as [CffuFactory.allResultsOfFastFail], providing this method is convenient for method chaining. - * - * If this array is not empty, `cffuFactory` argument is optional, use the `cffuFactory` of the first cffu element. - * If this array is empty and no`cffuFactory` provided, throw [IllegalArgumentException]. - * - * @see allOfFastFailCffu - * @see CffuFactory.allResultsOfFastFail - */ -fun Array>.allResultsOfFastFailCffu(cffuFactory: CffuFactory = ABSENT): Cffu> { - val factory: CffuFactory = if (cffuFactory !== ABSENT) cffuFactory - else firstOrNull()?.cffuFactory() ?: throw IllegalArgumentException(ERROR_MSG_FOR_ARRAY) - return factory.allResultsOfFastFail(*this) -} - -/** - * Returns a new Cffu with the results in the **same order** of the given stages arguments, - * the new Cffu success 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 [allOfFastFailCffu], except the returned Cffu contains the results of input Cffus. - * - * This method is the same as [CffuFactory.allResultsOfFastFail], providing this method is convenient for method chaining. - * - * @see allOfFastFailCffu - * @see CffuFactory.allResultsOfFastFail - */ -@JvmName("allResultsOfFastFailCffuCs") -fun Collection>.allResultsOfFastFailCffu(cffuFactory: CffuFactory): Cffu> = - cffuFactory.allResultsOfFastFail(*toTypedArray()) - -/** - * Returns a new Cffu with the results in the **same order** of the given stages arguments, - * the new Cffu success 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 [allOfFastFailCffu], except the returned Cffu contains the results of input Cffus. - * - * This method is the same as [CffuFactory.allResultsOfFastFail], providing this method is convenient for method chaining. - * - * @see allOfFastFailCffu - * @see CffuFactory.allResultsOfFastFail - */ -fun Array>.allResultsOfFastFailCffu(cffuFactory: CffuFactory): Cffu> = - cffuFactory.allResultsOfFastFail(*this) - /** * Returns a new Cffu that is successful when all the given Cffus success, * the results(`Cffu`) of the given Cffus are not reflected in the returned Cffu, @@ -390,92 +466,87 @@ fun Collection>.allOfFastFailCffu(cffuFactory: CffuFactory): fun Array>.allOfFastFailCffu(cffuFactory: CffuFactory): Cffu = cffuFactory.allOfFastFail(*this) +// endregion +//////////////////////////////////////////////////////////////////////////////// +// region# anyOf* methods for Collection/Array +//////////////////////////////////////////////////////////////////////////////// + /** - * Returns a new Cffu with the most results in the **same order** of - * the given Cffus arguments in the given time(`timeout`, aka as many results as possible in the given time). + * Returns a new Cffu that is successful when any of the given Cffus success, + * with the same result. Otherwise, all the given Cffus complete exceptionally, + * the returned Cffu also does so, with a CompletionException holding + * an exception from any of the given Cffus as its cause. If no Cffus are provided, + * returns a new Cffu that is already completed exceptionally with a CompletionException + * holding a [NoCfsProvidedException][io.foldright.cffu.NoCfsProvidedException] as its cause. * - * If the given Cffu is successful, its result is the completed value; Otherwise the given valueIfNotSuccess. + * This method is the same as [CffuFactory.anyOfSuccess], providing this method is convenient for method chaining. * - * @param timeout how long to wait in units of `unit` - * @param unit a `TimeUnit` determining how to interpret the `timeout` parameter - * @param valueIfNotSuccess the value to return if not completed successfully - * @see CffuFactory.mostResultsOfSuccess - * @see CffuFactory.mostTupleOfSuccess - * @see Cffu.getSuccessNow + * If this collection is not empty, `cffuFactory` argument is optional, use the `cffuFactory` of the first cffu element. + * If this collection is empty and no`cffuFactory` provided, throw [IllegalArgumentException]. + * + * @see anyOfCffu + * @see CffuFactory.anyOfSuccess */ -fun Collection>.mostResultsOfSuccessCffu( - valueIfNotSuccess: T, timeout: Long, unit: TimeUnit, cffuFactory: CffuFactory = ABSENT -): Cffu> { +fun Collection>.anyOfSuccessCffu(cffuFactory: CffuFactory = ABSENT): Cffu { val factory: CffuFactory = if (cffuFactory !== ABSENT) cffuFactory else firstOrNull()?.cffuFactory() ?: throw IllegalArgumentException(ERROR_MSG_FOR_COLL) - return factory.mostResultsOfSuccess(valueIfNotSuccess, timeout, unit, *toTypedArray()) + return factory.anyOfSuccess(*toTypedArray()) } /** - * Returns a new Cffu with the most results in the **same order** of - * the given Cffus arguments in the given time(`timeout`, aka as many results as possible in the given time). + * Returns a new Cffu that is successful when any of the given Cffus success, + * with the same result. Otherwise, all the given Cffus complete exceptionally, + * the returned Cffu also does so, with a CompletionException holding + * an exception from any of the given Cffus as its cause. If no Cffus are provided, + * returns a new Cffu that is already completed exceptionally with a CompletionException + * holding a [NoCfsProvidedException][io.foldright.cffu.NoCfsProvidedException] as its cause. * - * If the given Cffu is successful, its result is the completed value; Otherwise the given valueIfNotSuccess. + * This method is the same as [CffuFactory.anyOfSuccess], providing this method is convenient for method chaining. * - * @param timeout how long to wait in units of `unit` - * @param unit a `TimeUnit` determining how to interpret the `timeout` parameter - * @param valueIfNotSuccess the value to return if not completed successfully - * @see CffuFactory.mostResultsOfSuccess - * @see CffuFactory.mostTupleOfSuccess - * @see Cffu.getSuccessNow + * If this array is not empty, `cffuFactory` argument is optional, use the `cffuFactory` of the first cffu element. + * If this array is empty and no`cffuFactory` provided, throw [IllegalArgumentException]. + * + * @see anyOfCffu + * @see CffuFactory.anyOfSuccess */ -fun Array>.mostResultsOfSuccessCffu( - valueIfNotSuccess: T, timeout: Long, unit: TimeUnit, cffuFactory: CffuFactory = ABSENT -): Cffu> { +fun Array>.anyOfSuccessCffu(cffuFactory: CffuFactory = ABSENT): Cffu { val factory: CffuFactory = if (cffuFactory !== ABSENT) cffuFactory else firstOrNull()?.cffuFactory() ?: throw IllegalArgumentException(ERROR_MSG_FOR_ARRAY) - return factory.mostResultsOfSuccess(valueIfNotSuccess, timeout, unit, *this) + return factory.anyOfSuccess(*this) } /** - * Returns a new Cffu with the most results in the **same order** of - * the given stages arguments in the given time(`timeout`, aka as many results as possible in the given time). + * 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 [NoCfsProvidedException][io.foldright.cffu.NoCfsProvidedException] as its cause. * - * If the given stage is successful, its result is the completed value; Otherwise the given valueIfNotSuccess. + * This method is the same as [CffuFactory.anyOfSuccess], providing this method is convenient for method chaining. * - * @param timeout how long to wait in units of `unit` - * @param unit a `TimeUnit` determining how to interpret the `timeout` parameter - * @param valueIfNotSuccess the value to return if not completed successfully - * @see CffuFactory.mostResultsOfSuccess - * @see CffuFactory.mostTupleOfSuccess - * @see Cffu.getSuccessNow + * @see anyOfCffu + * @see CffuFactory.anyOfSuccess */ -@JvmName("mostResultsOfSuccessCffuCs") -fun Collection>.mostResultsOfSuccessCffu( - valueIfNotSuccess: T, timeout: Long, unit: TimeUnit, cffuFactory: CffuFactory -): Cffu> = - cffuFactory.mostResultsOfSuccess(valueIfNotSuccess, timeout, unit, *toTypedArray()) +@JvmName("anyOfSuccessCffuCs") +fun Collection>.anyOfSuccessCffu(cffuFactory: CffuFactory): Cffu = + cffuFactory.anyOfSuccess(*toTypedArray()) /** - * Returns a new Cffu with the most results in the **same order** of - * the given stages arguments in the given time(`timeout`, aka as many results as possible in the given time). + * 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 [NoCfsProvidedException][io.foldright.cffu.NoCfsProvidedException] as its cause. * - * If the given stage is successful, its result is the completed value; Otherwise the given valueIfNotSuccess. - * (aka the result extraction logic is [Cffu.getSuccessNow]). + * This method is the same as [CffuFactory.anyOfSuccess], providing this method is convenient for method chaining. * - * @param timeout how long to wait in units of `unit` - * @param unit a `TimeUnit` determining how to interpret the `timeout` parameter - * @param valueIfNotSuccess the value to return if not completed successfully - * @see CffuFactory.mostResultsOfSuccess - * @see CffuFactory.mostTupleOfSuccess - * @see Cffu.getSuccessNow + * @see anyOfCffu + * @see CffuFactory.anyOfSuccess */ -fun Array>.mostResultsOfSuccessCffu( - valueIfNotSuccess: T, timeout: Long, unit: TimeUnit, cffuFactory: CffuFactory -): Cffu> = - cffuFactory.mostResultsOfSuccess(valueIfNotSuccess, timeout, unit, *this) - -//////////////////////////////////////// -//# anyOf* methods for Array/Collection -// -// - anyOfCffu -// - anyOfSuccessCffu -//////////////////////////////////////// +fun Array>.anyOfSuccessCffu(cffuFactory: CffuFactory): Cffu = + cffuFactory.anyOfSuccess(*this) /** * Returns a new Cffu that is completed when any of the given Cffus complete, with the same result. @@ -530,86 +601,10 @@ fun Collection>.anyOfCffu(cffuFactory: CffuFactory): fun Array>.anyOfCffu(cffuFactory: CffuFactory): Cffu = cffuFactory.anyOf(*this) -/** - * Returns a new Cffu that is successful when any of the given Cffus success, - * with the same result. Otherwise, all the given Cffus complete exceptionally, - * the returned Cffu also does so, with a CompletionException holding - * an exception from any of the given Cffus as its cause. If no Cffus are provided, - * returns a new Cffu that is already completed exceptionally with a CompletionException - * holding a [NoCfsProvidedException][io.foldright.cffu.NoCfsProvidedException] as its cause. - * - * This method is the same as [CffuFactory.anyOfSuccess], providing this method is convenient for method chaining. - * - * If this collection is not empty, `cffuFactory` argument is optional, use the `cffuFactory` of the first cffu element. - * If this collection is empty and no`cffuFactory` provided, throw [IllegalArgumentException]. - * - * @see anyOfCffu - * @see CffuFactory.anyOfSuccess - */ -fun Collection>.anyOfSuccessCffu(cffuFactory: CffuFactory = ABSENT): Cffu { - val factory: CffuFactory = if (cffuFactory !== ABSENT) cffuFactory - else firstOrNull()?.cffuFactory() ?: throw IllegalArgumentException(ERROR_MSG_FOR_COLL) - return factory.anyOfSuccess(*toTypedArray()) -} - -/** - * Returns a new Cffu that is successful when any of the given Cffus success, - * with the same result. Otherwise, all the given Cffus complete exceptionally, - * the returned Cffu also does so, with a CompletionException holding - * an exception from any of the given Cffus as its cause. If no Cffus are provided, - * returns a new Cffu that is already completed exceptionally with a CompletionException - * holding a [NoCfsProvidedException][io.foldright.cffu.NoCfsProvidedException] as its cause. - * - * This method is the same as [CffuFactory.anyOfSuccess], providing this method is convenient for method chaining. - * - * If this array is not empty, `cffuFactory` argument is optional, use the `cffuFactory` of the first cffu element. - * If this array is empty and no`cffuFactory` provided, throw [IllegalArgumentException]. - * - * @see anyOfCffu - * @see CffuFactory.anyOfSuccess - */ -fun Array>.anyOfSuccessCffu(cffuFactory: CffuFactory = ABSENT): Cffu { - val factory: CffuFactory = if (cffuFactory !== ABSENT) cffuFactory - else firstOrNull()?.cffuFactory() ?: throw IllegalArgumentException(ERROR_MSG_FOR_ARRAY) - return factory.anyOfSuccess(*this) -} - -/** - * 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 [NoCfsProvidedException][io.foldright.cffu.NoCfsProvidedException] as its cause. - * - * This method is the same as [CffuFactory.anyOfSuccess], providing this method is convenient for method chaining. - * - * @see anyOfCffu - * @see CffuFactory.anyOfSuccess - */ -@JvmName("anyOfSuccessCffuCs") -fun Collection>.anyOfSuccessCffu(cffuFactory: CffuFactory): Cffu = - cffuFactory.anyOfSuccess(*toTypedArray()) - -/** - * 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 [NoCfsProvidedException][io.foldright.cffu.NoCfsProvidedException] as its cause. - * - * This method is the same as [CffuFactory.anyOfSuccess], providing this method is convenient for method chaining. - * - * @see anyOfCffu - * @see CffuFactory.anyOfSuccess - */ -fun Array>.anyOfSuccessCffu(cffuFactory: CffuFactory): Cffu = - cffuFactory.anyOfSuccess(*this) - -//////////////////////////////////////// -// cffuUnwrap methods for Array/Collection -//////////////////////////////////////// +// endregion +//////////////////////////////////////////////////////////////////////////////// +// region# cffuUnwrap methods for Collection/Array +//////////////////////////////////////////////////////////////////////////////// /** * Unwrap input [Cffu] collection elements by [Cffu.cffuUnwrap]. diff --git a/cffu-kotlin/src/main/java/io/foldright/cffu/kotlin/CffuTupleExtensions.kt b/cffu-kotlin/src/main/java/io/foldright/cffu/kotlin/CffuTupleExtensions.kt index e93f0d0d..beb38cf8 100644 --- a/cffu-kotlin/src/main/java/io/foldright/cffu/kotlin/CffuTupleExtensions.kt +++ b/cffu-kotlin/src/main/java/io/foldright/cffu/kotlin/CffuTupleExtensions.kt @@ -6,11 +6,11 @@ import io.foldright.cffu.tuple.Tuple4 import io.foldright.cffu.tuple.Tuple5 -//////////////////////////////////////////////////////////////////////////////// -// Destructuring declarations for cffu tuples -// -// https://kotlinlang.org/docs/destructuring-declarations.html -//////////////////////////////////////////////////////////////////////////////// +/* + This file contains the destructuring declarations for cffu tuples + + https://kotlinlang.org/docs/destructuring-declarations.html +*/ operator fun Tuple2.component1(): T1 = _1 operator fun Tuple2<*, T2>.component2(): T2 = _2 diff --git a/cffu-kotlin/src/main/java/io/foldright/cffu/kotlin/CompletableFutureExtensions.kt b/cffu-kotlin/src/main/java/io/foldright/cffu/kotlin/CompletableFutureExtensions.kt index a5e3b8ff..a9c7320f 100644 --- a/cffu-kotlin/src/main/java/io/foldright/cffu/kotlin/CompletableFutureExtensions.kt +++ b/cffu-kotlin/src/main/java/io/foldright/cffu/kotlin/CompletableFutureExtensions.kt @@ -10,135 +10,18 @@ import java.util.function.* import java.util.function.Function +/* + This file contains the Extension methods for CompletableFuture + input and output(return type) is CompletableFuture +*/ + //////////////////////////////////////////////////////////////////////////////// -//# Extension methods for CompletableFuture -// input and output(return type) is CompletableFuture +// region# CF Factory Methods //////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////// -//# allOf*/mostResultsOfSuccess* methods for Array/Collection -// -// - allOfCompletableFuture -// - allOfFastFailCompletableFuture -// - allResultsOfCompletableFuture -// - allResultsOfFastFailCompletableFuture -//////////////////////////////////////// - -/** - * 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, - * with a CompletionException holding this exception as its cause. - * Otherwise, the results, if any, of the given stages are not reflected - * in the returned CompletableFuture, but may be obtained by inspecting them individually. - * If no stages are provided, returns a CompletableFuture completed with the value `null`. - * - * If you need the results of given stages, prefer below methods: - * - * - [allResultsOfCompletableFuture] - * - * This method is the same as [CompletableFutureUtils.allOf], providing this method is convenient for method chaining. - * - * @see allResultsOfCompletableFuture - */ -fun Collection>.allOfCompletableFuture(): CompletableFuture = - CompletableFutureUtils.allOf(*toTypedArray()) - -/** - * 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, - * with a CompletionException holding this exception as its cause. - * Otherwise, the results, if any, of the given stages are not reflected - * in the returned CompletableFuture, but may be obtained by inspecting them individually. - * If no stages are provided, returns a CompletableFuture completed with the value `null`. - * - * If you need the results of given stages, prefer below methods: - * - * - [allResultsOfCompletableFuture] - * - * This method is the same as [CompletableFutureUtils.allOf], providing this method is convenient for method chaining. - * - * @see allResultsOfCompletableFuture - */ -fun Array>.allOfCompletableFuture(): CompletableFuture = - CompletableFutureUtils.allOf(*this) - -/** - * Returns a new CompletableFuture that is successful when all the given CompletableFutures success, - * the results(`CompletableFuture`) of the given CompletableFutures are not reflected in the returned CompletableFuture, - * but may be obtained by inspecting them individually. - * If any of the given CompletableFutures complete exceptionally, then the returned CompletableFuture - * also does so *without* waiting other incomplete given CompletableFutures, - * with a CompletionException holding this exception as its cause. - * If no CompletableFutures are provided, returns a CompletableFuture completed with the value `null`. - * - * If you need the results of given stages, prefer below methods: - * - * - [allResultsOfFastFailCompletableFuture] - * - * This method is the same as [CompletableFutureUtils.allOfFastFail], - * providing this method is convenient for method chaining. - * - * @see allResultsOfFastFailCompletableFuture - */ -fun Collection>.allOfFastFailCompletableFuture(): CompletableFuture = - CompletableFutureUtils.allOfFastFail(*toTypedArray()) - -/** - * Returns a new CompletableFuture that is successful when all the given CompletableFutures success, - * the results(`CompletableFuture`) of the given CompletableFutures are not reflected in the returned CompletableFuture, - * but may be obtained by inspecting them individually. - * If any of the given CompletableFutures complete exceptionally, then the returned CompletableFuture - * also does so *without* waiting other incomplete given CompletableFutures, - * with a CompletionException holding this exception as its cause. - * If no CompletableFutures are provided, returns a CompletableFuture completed with the value `null`. - * - * If you need the results of given stages, prefer below methods: - * - * - [allResultsOfFastFailCompletableFuture] - * - * This method is the same as [CompletableFutureUtils.allOfFastFail], - * providing this method is convenient for method chaining. - * - * @see allResultsOfFastFailCompletableFuture - */ -fun Array>.allOfFastFailCompletableFuture(): CompletableFuture = - CompletableFutureUtils.allOfFastFail(*this) - -/** - * Returns a new CompletableFuture with the results in the **same order** of all the given - * CompletableFutures arguments, the returned new CompletableFuture is completed when all the given CompletableFutures complete. - * If any of the given CompletableFutures complete exceptionally, then the returned CompletableFuture - * also does so, with a CompletionException holding this exception as its cause. - * If no CompletableFutures are provided, returns a CompletableFuture completed with the value empty list. - * - * This method is the same as [allOfCompletableFuture], - * except the returned CompletableFuture contains the results of input CompletableFutures. - * - * This method is the same as [CompletableFutureUtils.allResultsOf], - * providing this method is convenient for method chaining. - * - * @see allOfCompletableFuture - */ -fun Collection>.allResultsOfCompletableFuture(): CompletableFuture> = - CompletableFutureUtils.allResultsOf(*toTypedArray()) - -/** - * Returns a new CompletableFuture with the results in the **same order** of all the given - * CompletableFutures arguments, the returned new CompletableFuture is completed when all the given CompletableFutures complete. - * If any of the given CompletableFutures complete exceptionally, then the returned CompletableFuture - * also does so, with a CompletionException holding this exception as its cause. - * If no CompletableFutures are provided, returns a CompletableFuture completed with the value empty list. - * - * This method is the same as [allOfCompletableFuture], - * except the returned CompletableFuture contains the results of input CompletableFutures. - * - * This method is the same as [CompletableFutureUtils.allResultsOf], - * providing this method is convenient for method chaining. - * - * @see allOfCompletableFuture - */ -fun Array>.allResultsOfCompletableFuture(): CompletableFuture> = - CompletableFutureUtils.allResultsOf(*this) +//////////////////////////////////////////////////////////// +// region## allOf* Methods for Collection/Array(including mostResultsOfSuccess) +//////////////////////////////////////////////////////////// /** * Returns a new CompletableFuture with the results in the **same order** of all the given @@ -246,40 +129,126 @@ fun Array>.mostResultsOfSuccessCompletableFuture( ): CompletableFuture> = CompletableFutureUtils.mostResultsOfSuccess(valueIfNotSuccess, executorWhenTimeout, timeout, unit, *this) -//////////////////////////////////////// -//# anyOf* methods for Array/Collection -// -// - anyOfCompletableFuture -// - anyOfSuccessCompletableFuture -//////////////////////////////////////// +/** + * Returns a new CompletableFuture with the results in the **same order** of all the given + * CompletableFutures arguments, the returned new CompletableFuture is completed when all the given CompletableFutures complete. + * If any of the given CompletableFutures complete exceptionally, then the returned CompletableFuture + * also does so, with a CompletionException holding this exception as its cause. + * If no CompletableFutures are provided, returns a CompletableFuture completed with the value empty list. + * + * This method is the same as [allOfCompletableFuture], + * except the returned CompletableFuture contains the results of input CompletableFutures. + * + * This method is the same as [CompletableFutureUtils.allResultsOf], + * providing this method is convenient for method chaining. + * + * @see allOfCompletableFuture + */ +fun Collection>.allResultsOfCompletableFuture(): CompletableFuture> = + CompletableFutureUtils.allResultsOf(*toTypedArray()) /** - * Returns a new CompletableFuture that is completed - * when any of the given CompletableFutures complete, with the same result. - * Otherwise, if it completed exceptionally, the returned CompletableFuture also does so, + * Returns a new CompletableFuture with the results in the **same order** of all the given + * CompletableFutures arguments, the returned new CompletableFuture is completed when all the given CompletableFutures complete. + * If any of the given CompletableFutures complete exceptionally, then the returned CompletableFuture + * also does so, with a CompletionException holding this exception as its cause. + * If no CompletableFutures are provided, returns a CompletableFuture completed with the value empty list. + * + * This method is the same as [allOfCompletableFuture], + * except the returned CompletableFuture contains the results of input CompletableFutures. + * + * This method is the same as [CompletableFutureUtils.allResultsOf], + * providing this method is convenient for method chaining. + * + * @see allOfCompletableFuture + */ +fun Array>.allResultsOfCompletableFuture(): CompletableFuture> = + CompletableFutureUtils.allResultsOf(*this) + +/** + * 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, * with a CompletionException holding this exception as its cause. - * If no CompletableFutures are provided, returns an incomplete CompletableFuture. + * Otherwise, the results, if any, of the given stages are not reflected + * in the returned CompletableFuture, but may be obtained by inspecting them individually. + * If no stages are provided, returns a CompletableFuture completed with the value `null`. * - * This method is the same as [CompletableFutureUtils.anyOf], providing this method is convenient for method chaining. + * If you need the results of given stages, prefer below methods: * - * @see anyOfSuccessCompletableFuture + * - [allResultsOfCompletableFuture] + * + * This method is the same as [CompletableFutureUtils.allOf], providing this method is convenient for method chaining. + * + * @see allResultsOfCompletableFuture */ -fun Collection>.anyOfCompletableFuture(): CompletableFuture = - CompletableFutureUtils.anyOf(*toTypedArray()) +fun Collection>.allOfCompletableFuture(): CompletableFuture = + CompletableFutureUtils.allOf(*toTypedArray()) /** - * Returns a new CompletableFuture that is completed - * when any of the given CompletableFutures complete, with the same result. - * Otherwise, if it completed exceptionally, the returned CompletableFuture also does so, + * 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, * with a CompletionException holding this exception as its cause. - * If no CompletableFutures are provided, returns an incomplete CompletableFuture. + * Otherwise, the results, if any, of the given stages are not reflected + * in the returned CompletableFuture, but may be obtained by inspecting them individually. + * If no stages are provided, returns a CompletableFuture completed with the value `null`. * - * This method is the same as [CompletableFutureUtils.anyOf], providing this method is convenient for method chaining. + * If you need the results of given stages, prefer below methods: * - * @see anyOfSuccessCompletableFuture + * - [allResultsOfCompletableFuture] + * + * This method is the same as [CompletableFutureUtils.allOf], providing this method is convenient for method chaining. + * + * @see allResultsOfCompletableFuture */ -fun Array>.anyOfCompletableFuture(): CompletableFuture = - CompletableFutureUtils.anyOf(*this) +fun Array>.allOfCompletableFuture(): CompletableFuture = + CompletableFutureUtils.allOf(*this) + +/** + * Returns a new CompletableFuture that is successful when all the given CompletableFutures success, + * the results(`CompletableFuture`) of the given CompletableFutures are not reflected in the returned CompletableFuture, + * but may be obtained by inspecting them individually. + * If any of the given CompletableFutures complete exceptionally, then the returned CompletableFuture + * also does so *without* waiting other incomplete given CompletableFutures, + * with a CompletionException holding this exception as its cause. + * If no CompletableFutures are provided, returns a CompletableFuture completed with the value `null`. + * + * If you need the results of given stages, prefer below methods: + * + * - [allResultsOfFastFailCompletableFuture] + * + * This method is the same as [CompletableFutureUtils.allOfFastFail], + * providing this method is convenient for method chaining. + * + * @see allResultsOfFastFailCompletableFuture + */ +fun Collection>.allOfFastFailCompletableFuture(): CompletableFuture = + CompletableFutureUtils.allOfFastFail(*toTypedArray()) + +/** + * Returns a new CompletableFuture that is successful when all the given CompletableFutures success, + * the results(`CompletableFuture`) of the given CompletableFutures are not reflected in the returned CompletableFuture, + * but may be obtained by inspecting them individually. + * If any of the given CompletableFutures complete exceptionally, then the returned CompletableFuture + * also does so *without* waiting other incomplete given CompletableFutures, + * with a CompletionException holding this exception as its cause. + * If no CompletableFutures are provided, returns a CompletableFuture completed with the value `null`. + * + * If you need the results of given stages, prefer below methods: + * + * - [allResultsOfFastFailCompletableFuture] + * + * This method is the same as [CompletableFutureUtils.allOfFastFail], + * providing this method is convenient for method chaining. + * + * @see allResultsOfFastFailCompletableFuture + */ +fun Array>.allOfFastFailCompletableFuture(): CompletableFuture = + CompletableFutureUtils.allOfFastFail(*this) + +// endregion +//////////////////////////////////////////////////////////// +// region## anyOf* methods for Collection/Array +//////////////////////////////////////////////////////////// /** * Returns a new CompletableFuture that is successful when any of the given CompletableFutures success, @@ -313,118 +282,49 @@ fun Collection>.anyOfSuccessCompletableFuture(): Comp fun Array>.anyOfSuccessCompletableFuture(): CompletableFuture = CompletableFutureUtils.anyOfSuccess(*this) -//////////////////////////////////////////////////////////////////////////////// -//# `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 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 [CompletableFuture.runAfterBoth] except for the fast-fail behavior. - * - * @param action the action to perform before completing the returned CompletableFuture - * @return the new CompletableFuture - * @see CompletionStage.runAfterBoth - */ -fun CompletionStage<*>.runAfterBothFastFail(other: CompletionStage<*>, action: Runnable): CompletableFuture = - CompletableFutureUtils.runAfterBothFastFail(this, other, 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 [CompletableFuture.runAfterBothAsync] except for the fast-fail behavior. - * - * @param action the action to perform before completing the returned CompletableFuture - * @return the new CompletableFuture - * @see CompletionStage.runAfterBothAsync - */ -fun CompletionStage<*>.runAfterBothFastFailAsync(other: CompletionStage<*>, action: Runnable): CompletableFuture = - CompletableFutureUtils.runAfterBothFastFailAsync(this, other, 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, + * Returns a new CompletableFuture that is completed + * when any of the given CompletableFutures 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 CompletableFutures are provided, returns an incomplete CompletableFuture. * - * This method is the same as [CompletableFuture.runAfterBothAsync] except for the fast-fail behavior. + * This method is the same as [CompletableFutureUtils.anyOf], providing this method is convenient for method chaining. * - * @param action the action to perform before completing the returned CompletableFuture - * @return the new CompletableFuture - * @see CompletionStage.runAfterBothAsync + * @see anyOfSuccessCompletableFuture */ -fun CompletionStage<*>.runAfterBothFastFailAsync( - other: CompletionStage<*>, action: Runnable, executor: Executor -): CompletableFuture = - CompletableFutureUtils.runAfterBothFastFailAsync(this, other, action, executor) +fun Collection>.anyOfCompletableFuture(): CompletableFuture = + CompletableFutureUtils.anyOf(*toTypedArray()) /** - * 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, + * Returns a new CompletableFuture that is completed + * when any of the given CompletableFutures 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 CompletableFutures are provided, returns an incomplete CompletableFuture. * - * This method is the same as [CompletableFuture.thenAcceptBoth] except for the fast-fail behavior. + * This method is the same as [CompletableFutureUtils.anyOf], providing this method is convenient for method chaining. * - * @param action the action to perform before completing the returned CompletableFuture - * @return the new CompletableFuture - * @see CompletionStage.thenAcceptBoth + * @see anyOfSuccessCompletableFuture */ -fun CompletionStage.thenAcceptBothFastFail( - other: CompletionStage, action: BiConsumer -): CompletableFuture = - CompletableFutureUtils.thenAcceptBothFastFail(this, other, action) +fun Array>.anyOfCompletableFuture(): CompletableFuture = + CompletableFutureUtils.anyOf(*this) -/** - * 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 [CompletableFuture.thenAcceptBothAsync] except for the fast-fail behavior. - * - * @param action the action to perform before completing the returned CompletableFuture - * @return the new CompletableFuture - * @see CompletionStage.thenAcceptBothAsync - */ -fun CompletionStage.thenAcceptBothFastFailAsync( - other: CompletionStage, action: BiConsumer -): CompletableFuture = - CompletableFutureUtils.thenAcceptBothFastFailAsync(this, other, action) +// endregion +// endregion +//////////////////////////////////////////////////////////////////////////////// +// region# CF Instance Methods(including new enhanced + backport methods) +// +// backport CF instance methods compatibility for low Java version +//////////////////////////////////////////////////////////////////////////////// -/** - * 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 [CompletableFuture.thenAcceptBothAsync] except for the fast-fail behavior. - * - * @param action the action to perform before completing the returned CompletableFuture - * @return the new CompletableFuture - * @see CompletionStage.thenAcceptBothAsync - */ -fun CompletionStage.thenAcceptBothFastFailAsync( - other: CompletionStage, action: BiConsumer, executor: Executor -): CompletableFuture = - CompletableFutureUtils.thenAcceptBothFastFailAsync(this, other, action, executor) +//////////////////////////////////////////////////////////// +// 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, @@ -482,117 +382,119 @@ fun CompletionStage.thenCombineFastFailAsync( ): CompletableFuture = CompletableFutureUtils.thenCombineFastFailAsync(this, other, fn, 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 [CompletableFuture.runAfterEither] - * except for the either-**success** behavior(not either-**complete**). + * This method is the same as [CompletableFuture.thenAcceptBoth] except for the fast-fail behavior. * * @param action the action to perform before completing the returned CompletableFuture * @return the new CompletableFuture - * @see CompletionStage.runAfterEither + * @see CompletionStage.thenAcceptBoth */ -fun CompletionStage<*>.runAfterEitherSuccess(other: CompletionStage<*>, action: Runnable): CompletableFuture = - CompletableFutureUtils.runAfterEitherSuccess(this, other, action) +fun CompletionStage.thenAcceptBothFastFail( + other: CompletionStage, action: BiConsumer +): CompletableFuture = + CompletableFutureUtils.thenAcceptBothFastFail(this, other, action) /** - * 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 [CompletableFuture.runAfterEitherAsync] - * except for the either-**success** behavior(not either-**complete**). + * This method is the same as [CompletableFuture.thenAcceptBothAsync] except for the fast-fail behavior. * * @param action the action to perform before completing the returned CompletableFuture * @return the new CompletableFuture - * @see CompletionStage.runAfterEitherAsync + * @see CompletionStage.thenAcceptBothAsync */ -fun CompletionStage<*>.runAfterEitherSuccessAsync( - other: CompletionStage<*>, action: Runnable +fun CompletionStage.thenAcceptBothFastFailAsync( + other: CompletionStage, action: BiConsumer ): CompletableFuture = - CompletableFutureUtils.runAfterEitherSuccessAsync(this, other, action) + CompletableFutureUtils.thenAcceptBothFastFailAsync(this, other, action) /** - * 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 [CompletableFuture.runAfterEitherAsync] - * except for the either-**success** behavior(not either-**complete**). + * This method is the same as [CompletableFuture.thenAcceptBothAsync] except for the fast-fail behavior. * * @param action the action to perform before completing the returned CompletableFuture * @return the new CompletableFuture - * @see CompletionStage.runAfterEitherAsync + * @see CompletionStage.thenAcceptBothAsync */ -fun CompletionStage<*>.runAfterEitherSuccessAsync( - other: CompletionStage<*>, action: Runnable, executor: Executor +fun CompletionStage.thenAcceptBothFastFailAsync( + other: CompletionStage, action: BiConsumer, executor: Executor ): CompletableFuture = - CompletableFutureUtils.runAfterEitherSuccessAsync(this, other, action, executor) + CompletableFutureUtils.thenAcceptBothFastFailAsync(this, other, action, 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 [CompletableFuture.acceptEither] - * except for the either-**success** behavior(not either-**complete**). + * This method is the same as [CompletableFuture.runAfterBoth] except for the fast-fail behavior. * * @param action the action to perform before completing the returned CompletableFuture * @return the new CompletableFuture - * @see CompletionStage.acceptEither + * @see CompletionStage.runAfterBoth */ -fun CompletionStage.acceptEitherSuccess( - other: CompletionStage, action: Consumer -): CompletableFuture = - CompletableFutureUtils.acceptEitherSuccess(this, other, action) +fun CompletionStage<*>.runAfterBothFastFail(other: CompletionStage<*>, action: Runnable): CompletableFuture = + CompletableFutureUtils.runAfterBothFastFail(this, other, action) /** - * Returns a new CompletionStage that, when either given stage success, - * is executed using this stage'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 [CompletableFuture.acceptEitherAsync] - * except for the either-**success** behavior(not either-**complete**). + * This method is the same as [CompletableFuture.runAfterBothAsync] except for the fast-fail behavior. * * @param action the action to perform before completing the returned CompletableFuture * @return the new CompletableFuture - * @see CompletionStage.acceptEitherAsync + * @see CompletionStage.runAfterBothAsync */ -fun CompletionStage.acceptEitherSuccessAsync( - other: CompletionStage, action: Consumer -): CompletableFuture = - CompletableFutureUtils.acceptEitherSuccessAsync(this, other, action) +fun CompletionStage<*>.runAfterBothFastFailAsync(other: CompletionStage<*>, action: Runnable): CompletableFuture = + CompletableFutureUtils.runAfterBothFastFailAsync(this, other, action) /** - * Returns a new CompletionStage 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 [CompletableFuture.acceptEitherAsync] - * except for the either-**success** behavior(not either-**complete**). + * This method is the same as [CompletableFuture.runAfterBothAsync] 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 + * @see CompletionStage.runAfterBothAsync */ -fun CompletionStage.acceptEitherSuccessAsync( - other: CompletionStage, action: Consumer, executor: Executor +fun CompletionStage<*>.runAfterBothFastFailAsync( + other: CompletionStage<*>, action: Runnable, executor: Executor ): CompletableFuture = - CompletableFutureUtils.acceptEitherSuccessAsync(this, other, action, executor) + CompletableFutureUtils.runAfterBothFastFailAsync(this, other, 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 CompletionStage that, when either given stage success, @@ -647,94 +549,114 @@ fun CompletionStage.applyToEitherSuccessAsync( ): CompletableFuture = CompletableFutureUtils.applyToEitherSuccessAsync(this, other, fn, executor) -//////////////////////////////////////////////////////////////////////////////// -//# New enhanced methods -//////////////////////////////////////////////////////////////////////////////// - /** - * Peeks the result by executing the given action when this stage completes, returns this stage. - * - * When this stage is complete, the given action is invoked with the result (or `null` if none) - * and the exception (or `null` if none) of given stage as arguments. Whether the supplied action - * throws an exception or not, this 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 [handle][CompletionStage.handle] and like method [whenComplete][CompletionStage.whenComplete], - * this method is not designed to translate completion outcomes. + * This method is the same as [CompletableFuture.acceptEither] + * except for the either-**success** behavior(not either-**complete**). * - * @param action the action to perform - * @return this stage - * @see CompletionStage.whenComplete - * @see java.util.stream.Stream.peek + * @param action the action to perform before completing the returned CompletableFuture + * @return the new CompletableFuture + * @see CompletionStage.acceptEither */ -fun > C.peek(action: BiConsumer): C = - CompletableFutureUtils.peek(this, action) +fun CompletionStage.acceptEitherSuccess( + other: CompletionStage, action: Consumer +): CompletableFuture = + CompletableFutureUtils.acceptEitherSuccess(this, other, action) /** - * Peeks the result by executing the given action when this stage completes, - * executes the given action using this stage's default asynchronous execution facility, returns this stage. - * - * When this stage is complete, the given action is invoked with the result (or `null` if none) - * and the exception (or `null` if none) of given stage as arguments. Whether the supplied action - * throws an exception or not, this stage is **NOT** affected. + * Returns a new CompletionStage that, when either given stage success, + * is executed using this stage's default asynchronous execution facility, + * with the corresponding result as argument to the supplied action. * - * Unlike method [handle][CompletionStage.handle] and like method [whenComplete][CompletionStage.whenComplete], - * this method is not designed to translate completion outcomes. + * This method is the same as [CompletableFuture.acceptEitherAsync] + * except for the either-**success** behavior(not either-**complete**). * - * @param action the action to perform - * @return this stage - * @see CompletionStage.whenCompleteAsync - * @see java.util.stream.Stream.peek + * @param action the action to perform before completing the returned CompletableFuture + * @return the new CompletableFuture + * @see CompletionStage.acceptEitherAsync */ -fun > C.peekAsync(action: BiConsumer): C = - CompletableFutureUtils.peekAsync(this, action) +fun CompletionStage.acceptEitherSuccessAsync( + other: CompletionStage, action: Consumer +): CompletableFuture = + CompletableFutureUtils.acceptEitherSuccessAsync(this, other, action) /** - * Peeks the result by executing the given action when this stage completes, - * executes the given action using the supplied Executor, returns this stage. - * - * When this stage is complete, the given action is invoked with the result (or `null` if none) - * and the exception (or `null` if none) of given stage as arguments. Whether the supplied action - * throws an exception or not, this stage is **NOT** affected. + * Returns a new CompletionStage that, when either given stage success, + * is executed using the supplied executor, with the corresponding result as argument to the supplied action. * - * Unlike method [handle][CompletionStage.handle] and like method [whenComplete][CompletionStage.whenComplete], - * this method is not designed to translate completion outcomes. + * This method is the same as [CompletableFuture.acceptEitherAsync] + * except for the either-**success** behavior(not either-**complete**). * - * @param action the action to perform - * @return this stage - * @see CompletionStage.whenCompleteAsync - * @see java.util.stream.Stream.peek + * @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 */ -fun > C.peekAsync(action: BiConsumer, executor: Executor): C = - CompletableFutureUtils.peekAsync(this, action, executor) - -//////////////////////////////////////// -// toCompletableFuture methods -//////////////////////////////////////// +fun CompletionStage.acceptEitherSuccessAsync( + other: CompletionStage, action: Consumer, executor: Executor +): CompletableFuture = + CompletableFutureUtils.acceptEitherSuccessAsync(this, other, action, executor) /** - * Convert [CompletionStage] (including [Cffu]) collection elements to [CompletableFuture]. + * 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. * - * This method is the same as [CompletableFutureUtils.toCompletableFutureArray], - * providing this method is convenient for method chaining. + * This method is the same as [CompletableFuture.runAfterEither] + * except for the either-**success** behavior(not either-**complete**). + * + * @param action the action to perform before completing the returned CompletableFuture + * @return the new CompletableFuture + * @see CompletionStage.runAfterEither */ -fun Collection>.toCompletableFuture(): List> = - map { it.toCompletableFuture() } +fun CompletionStage<*>.runAfterEitherSuccess(other: CompletionStage<*>, action: Runnable): CompletableFuture = + CompletableFutureUtils.runAfterEitherSuccess(this, other, action) /** - * Convert [CompletionStage] (including [Cffu]) array elements to [CompletableFuture]. + * 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 [CompletableFutureUtils.toCompletableFutureArray], - * providing this method is convenient for method chaining. + * This method is the same as [CompletableFuture.runAfterEitherAsync] + * except for the either-**success** behavior(not either-**complete**). + * + * @param action the action to perform before completing the returned CompletableFuture + * @return the new CompletableFuture + * @see CompletionStage.runAfterEitherAsync */ -fun Array>.toCompletableFuture(): Array> = - CompletableFutureUtils.toCompletableFutureArray(*this) +fun CompletionStage<*>.runAfterEitherSuccessAsync( + other: CompletionStage<*>, action: Runnable +): CompletableFuture = + CompletableFutureUtils.runAfterEitherSuccessAsync(this, other, action) -//////////////////////////////////////////////////////////////////////////////// -//# Backport CF instance methods -// compatibility for low Java version -//////////////////////////////////////////////////////////////////////////////// +/** + * 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 [CompletableFuture.runAfterEitherAsync] + * except for the either-**success** behavior(not either-**complete**). + * + * @param action the action to perform before completing the returned CompletableFuture + * @return the new CompletableFuture + * @see CompletionStage.runAfterEitherAsync + */ +fun CompletionStage<*>.runAfterEitherSuccessAsync( + other: CompletionStage<*>, action: Runnable, executor: Executor +): CompletableFuture = + CompletableFutureUtils.runAfterEitherSuccessAsync(this, other, 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 @@ -762,7 +684,10 @@ fun > C.exceptionallyAsync(fn: Function> C.exceptionallyAsync(fn: Function, executor: Executor): C = CompletableFutureUtils.exceptionallyAsync(this, fn, executor) -//# Timeout Control methods +// endregion +//////////////////////////////////////////////////////////// +// region## Timeout Control Methods of CompletableFuture +//////////////////////////////////////////////////////////// /** * Exceptionally completes this CompletableFuture with a TimeoutException @@ -872,7 +797,14 @@ fun > C.cffuCompleteOnTimeout( fun > C.completeOnTimeout(value: T, timeout: Long, unit: TimeUnit): C = CompletableFutureUtils.completeOnTimeout(this, value, timeout, unit) -//# Advanced methods of CompletionStage +// endregion +//////////////////////////////////////////////////////////// +// region## Advanced Methods of CompletionStage(compose* and handle-like methods) +// +// NOTE about advanced meaning: +// - `compose` methods, input function argument return CompletionStage +// - handle successful and failed result together(handle*/whenComplete*/peek*) +//////////////////////////////////////////////////////////// /** * Returns a new CompletionStage that, when given stage completes exceptionally, @@ -911,7 +843,66 @@ fun > C.exceptionallyComposeAsync( ): C = CompletableFutureUtils.exceptionallyComposeAsync(this, fn, executor) -//# Read(explicitly) methods of CompletableFuture +/** + * Peeks the result by executing the given action when this stage completes, returns this stage. + * + * When this stage is complete, the given action is invoked with the result (or `null` if none) + * and the exception (or `null` if none) of given stage as arguments. Whether the supplied action + * throws an exception or not, this stage is **NOT** affected. + * + * Unlike method [handle][CompletionStage.handle] and like method [whenComplete][CompletionStage.whenComplete], + * this method is not designed to translate completion outcomes. + * + * @param action the action to perform + * @return this stage + * @see CompletionStage.whenComplete + * @see java.util.stream.Stream.peek + */ +fun > C.peek(action: BiConsumer): C = + CompletableFutureUtils.peek(this, action) + +/** + * Peeks the result by executing the given action when this stage completes, + * executes the given action using this stage's default asynchronous execution facility, returns this stage. + * + * When this stage is complete, the given action is invoked with the result (or `null` if none) + * and the exception (or `null` if none) of given stage as arguments. Whether the supplied action + * throws an exception or not, this stage is **NOT** affected. + * + * Unlike method [handle][CompletionStage.handle] and like method [whenComplete][CompletionStage.whenComplete], + * this method is not designed to translate completion outcomes. + * + * @param action the action to perform + * @return this stage + * @see CompletionStage.whenCompleteAsync + * @see java.util.stream.Stream.peek + */ +fun > C.peekAsync(action: BiConsumer): C = + CompletableFutureUtils.peekAsync(this, action) + +/** + * Peeks the result by executing the given action when this stage completes, + * executes the given action using the supplied Executor, returns this stage. + * + * When this stage is complete, the given action is invoked with the result (or `null` if none) + * and the exception (or `null` if none) of given stage as arguments. Whether the supplied action + * throws an exception or not, this stage is **NOT** affected. + * + * Unlike method [handle][CompletionStage.handle] and like method [whenComplete][CompletionStage.whenComplete], + * this method is not designed to translate completion outcomes. + * + * @param action the action to perform + * @return this stage + * @see CompletionStage.whenCompleteAsync + * @see java.util.stream.Stream.peek + */ +fun > C.peekAsync(action: BiConsumer, executor: Executor): C = + CompletableFutureUtils.peekAsync(this, action, executor) + +// endregion +//////////////////////////////////////////////////////////// +// region## Read(explicitly) Methods of CompletableFuture(including Future) +//////////////////////////////////////////////////////////// /** * Waits if necessary for at most the given time for the computation to complete, @@ -994,7 +985,10 @@ fun Future<*>.exceptionNow(): Throwable = fun Future<*>.cffuState(): CffuState = CompletableFutureUtils.state(this) -//# Write methods of CompletableFuture +// endregion +//////////////////////////////////////////////////////////// +// region## Write Methods of CompletableFuture +//////////////////////////////////////////////////////////// /** * Completes given CompletableFuture with the result of the given Supplier function invoked @@ -1040,7 +1034,10 @@ fun > C.completeExceptionallyAsync(supplier: Supplier> C.completeExceptionallyAsync(supplier: Supplier, executor: Executor): C = CompletableFutureUtils.completeExceptionallyAsync(this, supplier, executor) -//# 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 @@ -1077,3 +1074,28 @@ fun CompletableFuture.copy(): CompletableFuture = */ fun CompletableFuture<*>.newIncompleteFuture(): CompletableFuture = CompletableFutureUtils.newIncompleteFuture(this) + +// endregion +// endregion +//////////////////////////////////////////////////////////////////////////////// +// region# toCompletableFuture Conversion Methods for Collection/Array +//////////////////////////////////////////////////////////////////////////////// + +/** + * Convert [CompletionStage] (including [Cffu]) collection elements to [CompletableFuture]. + * + * This method is the same as [CompletableFutureUtils.toCompletableFutureArray], + * providing this method is convenient for method chaining. + */ +fun Collection>.toCompletableFuture(): List> = + map { it.toCompletableFuture() } + +/** + * Convert [CompletionStage] (including [Cffu]) array elements to [CompletableFuture]. + * + * This method is the same as [CompletableFutureUtils.toCompletableFutureArray], + * providing this method is convenient for method chaining. + */ +fun Array>.toCompletableFuture(): Array> = + CompletableFutureUtils.toCompletableFutureArray(*this) +