Class AsyncFut
Asyncc. Each combinator returns a
CompletableFuture instead of taking an error-first final callback — the same
vocabulary, the JDK's promise shape.
AsyncFut is implemented in terms of Asyncc (via WrapFuture), so
every combinator inherits the v0.2.x concurrency hardening: at-most-once final callback,
lost-update-free counters, slot-write-before-counter-increment ordering, no
ArrayList resize race, the ParallelLimit <= limit-in-flight
invariant, etc. The wrapper layer adds one CompletableFuture allocation per call;
use Asyncc directly if you need to shave that ~5 µs.
Task shape
Most combinators take a list (or function) of Suppliers that produce a
CompletionStage. The supplier is invoked when the combinator chooses to start that
task — this is crucial for Series, ParallelLimit, and Race,
where eagerly-started futures would defeat the point. If you already have an in-flight
future, wrap it as () -> theFuture.
Quick examples
// Parallel: fan out N tasks, collect their results
CompletableFuture<List<String>> both = AsyncFut.Parallel(List.of(
() -> CompletableFuture.supplyAsync(this::fetchA, exec),
() -> CompletableFuture.supplyAsync(this::fetchB, exec)
));
both.thenAccept(results -> reply.send(combine(results.get(0), results.get(1))));
// ParallelLimit: same but with a concurrency cap
CompletableFuture<List<Path>> downloaded = AsyncFut.ParallelLimit(8, downloads);
// Series: sequential, collect each result
CompletableFuture<List<Step>> chain = AsyncFut.Series(List.of(
() -> validate(req), () -> persist(req), () -> notify(req)
));
// Race: first completer wins
CompletableFuture<String> winner = AsyncFut.Race(List.of(
() -> fromPrimary(), () -> fromReplica()
));
// Map: async transform preserving input order
CompletableFuture<List<Profile>> profiles =
AsyncFut.Map(userIds, id -> fetchProfileAsync(id));
// Reduce: sequential fold with an async reducer
CompletableFuture<BigDecimal> total =
AsyncFut.Reduce(transactions, BigDecimal.ZERO,
(acc, txn) -> computeAsync(acc, txn));
// Times: run the same task N times
CompletableFuture<List<Sample>> samples =
AsyncFut.Times(8, i -> generateSampleAsync(i));
// Each: fire-and-forget per element, complete with Void when all done
CompletableFuture<Void> sent =
AsyncFut.Each(users, u -> sendEmailAsync(u));
Error semantics
Each combinator's returned future completes exceptionally with the first error any task
produces (just like Asyncc's short-circuit). Subsequent task completions are
absorbed by the at-most-once guard.
Interop
You can mix Asyncc and AsyncFut freely via WrapFuture:
// AsyncFut.Parallel inside an Asyncc.Waterfall step:
Asyncc.Waterfall(List.of(
c -> c.success(parseRequest(raw)),
(req, c) -> WrapFuture.fromStage(
AsyncFut.Parallel(List.of(
() -> lookupA(req), () -> lookupB(req)
))
).run(c)
), wrap(finalValue -> reply.send(finalValue)));
- Since:
- 0.2.7
- See Also:
-
Method Summary
Modifier and TypeMethodDescriptionstatic <T> CompletableFuture<List<T>>DoWhilst(BooleanSupplier test, Supplier<? extends CompletionStage<T>> body) LikeWhilst(java.util.function.BooleanSupplier, java.util.function.Supplier<? extends java.util.concurrent.CompletionStage<T>>)but runsbodyat least once before consultingtest.static <T> CompletableFuture<Void>Each(int limit, Iterable<T> input, Function<? super T, ? extends CompletionStage<Void>> task) Fire-and-forget per element with a concurrency cap.static <T> CompletableFuture<Void>Each(Iterable<T> input, Function<? super T, ? extends CompletionStage<Void>> task) Unlimited-concurrency convenience forEach(int, Iterable, Function).static <T,V> CompletableFuture<List<V>> FilterMap(Iterable<T> input, Function<? super T, ? extends CompletionStage<V>> mapper) Async map + filter.static <T> CompletableFuture<Map<String,List<T>>> GroupBy(Iterable<T> input, Function<? super T, ? extends CompletionStage<String>> keyer) Bucket each element by an async-computed string key.static <T,V> CompletableFuture<List<V>> Map(Iterable<T> input, Function<? super T, ? extends CompletionStage<V>> mapper) Runmapper(element)concurrently for each element ofinput; return a future of the per-element values in input order.static <T> CompletableFuture<List<T>>Parallel(Supplier<? extends CompletionStage<T>> a, Supplier<? extends CompletionStage<T>> b) Two-task convenience.static <T> CompletableFuture<List<T>>Parallel(Supplier<? extends CompletionStage<T>> a, Supplier<? extends CompletionStage<T>> b, Supplier<? extends CompletionStage<T>> c) Three-task convenience.static <T> CompletableFuture<List<T>>Parallel(List<Supplier<? extends CompletionStage<T>>> tasks) Run all tasks concurrently; return a future of their results in the same order as the input list.static <T> CompletableFuture<List<T>>ParallelF(List<? extends CompletionStage<T>> futures) static <T> CompletableFuture<List<T>>ParallelLimit(int limit, List<Supplier<? extends CompletionStage<T>>> tasks) LikeParallel(java.util.List<java.util.function.Supplier<? extends java.util.concurrent.CompletionStage<T>>>)but with at mostlimittasks in flight at any time.static <T> CompletableFuture<T>Race(List<Supplier<? extends CompletionStage<T>>> tasks) Run all tasks concurrently; complete with the value of whichever finishes first.static <T> CompletableFuture<T>RaceF(List<? extends CompletionStage<T>> futures) LikeRace, but accepts already-startedCompletionStages.static <T,V> CompletableFuture<V> Reduce(Iterable<T> input, V identity, BiFunction<V, ? super T, ? extends CompletionStage<V>> reducer) Sequential fold with an async reducer.static <T> CompletableFuture<List<T>>Series(List<Supplier<? extends CompletionStage<T>>> tasks) Run tasks one after another.static <T> CompletableFuture<List<T>>Times(int n, IntFunction<? extends CompletionStage<T>> task) Runtask(i)foriin[0, n)concurrently; return a future of the per-iteration results iniorder.static CompletableFuture<Map<String,Object>> Waterfall(List<Function<Map<String, Object>, ? extends CompletionStage<Map.Entry<String, Object>>>> steps) Sequential pipeline with a named accumulator.static <T> CompletableFuture<List<T>>Whilst(BooleanSupplier test, Supplier<? extends CompletionStage<T>> body) Async while-loop.
-
Method Details
-
Parallel
public static <T> CompletableFuture<List<T>> Parallel(List<Supplier<? extends CompletionStage<T>>> tasks) Run all tasks concurrently; return a future of their results in the same order as the input list. Short-circuits on the first failure. -
Parallel
public static <T> CompletableFuture<List<T>> Parallel(Supplier<? extends CompletionStage<T>> a, Supplier<? extends CompletionStage<T>> b) Two-task convenience. -
Parallel
public static <T> CompletableFuture<List<T>> Parallel(Supplier<? extends CompletionStage<T>> a, Supplier<? extends CompletionStage<T>> b, Supplier<? extends CompletionStage<T>> c) Three-task convenience. -
ParallelLimit
public static <T> CompletableFuture<List<T>> ParallelLimit(int limit, List<Supplier<? extends CompletionStage<T>>> tasks) LikeParallel(java.util.List<java.util.function.Supplier<? extends java.util.concurrent.CompletionStage<T>>>)but with at mostlimittasks in flight at any time. -
Series
public static <T> CompletableFuture<List<T>> Series(List<Supplier<? extends CompletionStage<T>>> tasks) Run tasks one after another. The returned future completes with a list of each task's value in input order. Short-circuits on the first failure. -
ParallelF
LikeParallel, but accepts already-startedCompletionStages directly instead ofSuppliers. Use this for clean nested composition where the inner combinators have already returned their futures:// before (one extra `() ->` per task to defer the start): CompletableFuture<List<List<X>>> nested = AsyncFut.Parallel(List.of( () -> AsyncFut.Series(seriesTasks), () -> AsyncFut.Parallel(parallelTasks) )); // after (drop the supplier wrappers): CompletableFuture<List<List<X>>> nested = AsyncFut.ParallelF(List.of( AsyncFut.Series(seriesTasks), AsyncFut.Parallel(parallelTasks) ));Semantic difference vs
Parallel: this variant doesn't control when the tasks start — they're already in flight by the time the list is built. For top-level fan-out that's exactly what you want; forSeries-style ordering it'd defeat the purpose (use theSupplier-takingSeriesfor that).- Since:
- 0.2.8
-
RaceF
- Since:
- 0.2.8
-
Race
Run all tasks concurrently; complete with the value of whichever finishes first. Errors from non-winning tasks are absorbed by the at-most-once guard. -
Map
public static <T,V> CompletableFuture<List<V>> Map(Iterable<T> input, Function<? super T, ? extends CompletionStage<V>> mapper) Runmapper(element)concurrently for each element ofinput; return a future of the per-element values in input order. -
Reduce
public static <T,V> CompletableFuture<V> Reduce(Iterable<T> input, V identity, BiFunction<V, ? super T, ? extends CompletionStage<V>> reducer) Sequential fold with an async reducer.reducer(acc, element)is invoked once per element, in input order, with the running accumulator. The returned future completes with the final accumulator value. -
Times
public static <T> CompletableFuture<List<T>> Times(int n, IntFunction<? extends CompletionStage<T>> task) Runtask(i)foriin[0, n)concurrently; return a future of the per-iteration results iniorder. -
Each
public static <T> CompletableFuture<Void> Each(int limit, Iterable<T> input, Function<? super T, ? extends CompletionStage<Void>> task) Fire-and-forget per element with a concurrency cap.task(element)runs for each element concurrently up tolimitin-flight; the returned future completes withnullwhen all tasks finish, or exceptionally on the first failure. No per-element value is collected. -
Each
public static <T> CompletableFuture<Void> Each(Iterable<T> input, Function<? super T, ? extends CompletionStage<Void>> task) Unlimited-concurrency convenience forEach(int, Iterable, Function). -
Waterfall
public static CompletableFuture<Map<String,Object>> Waterfall(List<Function<Map<String, Object>, ? extends CompletionStage<Map.Entry<String, Object>>>> steps) Sequential pipeline with a named accumulator. Each step receives a snapshot of the accumulated map so far and returns aCompletionStageproducing a single(key, value)entry to add to the accumulator. The returned future completes with the final accumulator map.This mirrors
Asyncc.Waterfall(List, Asyncc.IAsyncCallback)'s named-accumulator shape (theHashMap<String, Object>you get back from the callback form), adapted forCompletionStage-returning steps.If a step's stage emits
nullas the entry, that step is skipped (no entry is added) but the pipeline continues. If a step's stage completes exceptionally, the pipeline short-circuits and the returned future completes exceptionally.CompletableFuture<Map<String, Object>> fut = AsyncFut.Waterfall(List.of( acc -> fetchConfigAsync().thenApply(cfg -> Map.entry("config", cfg)), acc -> fetchShardsAsync().thenApply(shs -> Map.entry("shards", shs)), acc -> enrichAsync(acc).thenApply(enr -> Map.entry("enriched", enr)) )); fut.thenAccept(acc -> reply.send(buildManifest(acc))); -
FilterMap
public static <T,V> CompletableFuture<List<V>> FilterMap(Iterable<T> input, Function<? super T, ? extends CompletionStage<V>> mapper) Async map + filter. Themapperis applied to each element; if the returned stage completes withnull, the element is dropped from the result. Order is preserved across the surviving elements.CompletableFuture<List<Profile>> active = AsyncFut.FilterMap(candidateIds, id -> fetchProfileAsync(id) .thenApply(p -> p.isActive() ? p : null)); -
GroupBy
public static <T> CompletableFuture<Map<String,List<T>>> GroupBy(Iterable<T> input, Function<? super T, ? extends CompletionStage<String>> keyer) Bucket each element by an async-computed string key. The returned future completes with aMap<String, List<T>>where each entry is the list of elements that produced that key, in input order within the bucket.CompletableFuture<Map<String, List<User>>> byRegion = AsyncFut.GroupBy(users, u -> resolveRegionAsync(u)); -
Whilst
public static <T> CompletableFuture<List<T>> Whilst(BooleanSupplier test, Supplier<? extends CompletionStage<T>> body) Async while-loop.testis invoked synchronously before each iteration; if true,bodyis invoked and its result added to the collected list. Loop terminates the first timetestreturns false, or as soon asbodyfails. The returned future completes with the list of all per-iteration values.AtomicInteger counter = new AtomicInteger(); CompletableFuture<List<Page>> pages = AsyncFut.Whilst( () -> counter.get() < pageCount, () -> fetchPageAsync(counter.getAndIncrement())); -
DoWhilst
public static <T> CompletableFuture<List<T>> DoWhilst(BooleanSupplier test, Supplier<? extends CompletionStage<T>> body) LikeWhilst(java.util.function.BooleanSupplier, java.util.function.Supplier<? extends java.util.concurrent.CompletionStage<T>>)but runsbodyat least once before consultingtest.
-