Class AsyncFut

java.lang.Object
org.ores.async.AsyncFut

public final class AsyncFut extends Object
Promise-returning sibling to 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 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)
    • 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

      public static <T> CompletableFuture<List<T>> ParallelF(List<? extends CompletionStage<T>> futures)
      Like Parallel, but accepts already-started CompletionStages directly instead of Suppliers. 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; for Series-style ordering it'd defeat the purpose (use the Supplier-taking Series for that).

      Since:
      0.2.8
    • RaceF

      public static <T> CompletableFuture<T> RaceF(List<? extends CompletionStage<T>> futures)
      Like Race, but accepts already-started CompletionStages. See ParallelF(List) for the rationale.
      Since:
      0.2.8
    • Race

      public static <T> CompletableFuture<T> Race(List<Supplier<? extends CompletionStage<T>>> tasks)
      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)
      Run mapper(element) concurrently for each element of input; 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)
      Run task(i) for i in [0, n) concurrently; return a future of the per-iteration results in i order.
    • 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 to limit in-flight; the returned future completes with null when 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 for Each(int, Iterable, Function).
    • Waterfall

      Sequential pipeline with a named accumulator. Each step receives a snapshot of the accumulated map so far and returns a CompletionStage producing 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 (the HashMap<String, Object> you get back from the callback form), adapted for CompletionStage-returning steps.

      If a step's stage emits null as 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. The mapper is applied to each element; if the returned stage completes with null, 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 a Map<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. test is invoked synchronously before each iteration; if true, body is invoked and its result added to the collected list. Loop terminates the first time test returns false, or as soon as body fails. 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)