Class FutureStreamJoiner

java.lang.Object
com.github.mizool.core.concurrent.FutureStreamJoiner

public final class FutureStreamJoiner extends Object
Joins a stream of futures, returning a single joint future. Accumulation or reduction of results is intentionally not supported, so all futures must be of (or converted to) type Void (see below).

The stream is consumed as fast as possible without the number of incomplete futures exceeding concurrencyLimit. The stream consumer is executed by the given ExecutorService.

Exceptional completion of futures

  • When one or more of the futures inside the stream complete exceptionally, so does the joint future. After that, one more future will be consumed from the stream, but the joint future will not wait for it to complete.
  • The Throwable result of the joint future will be that of the first future to complete exceptionally; others will be lost.
  • As with other futures, the throwable result of a computation will be wrapped inside an ExecutionException, e.g. when invoking get(). Note that this happens regardless of the type of throwable (checked exception, runtime exception, error).

Exceptions thrown by the original stream

If the original stream throws an exception instead of producing a future, the joint future will behave the same way as with exceptional completion of futures: the exception will be wrapped inside an ExecutionException, e.g. when invoking get().

Usage examples


 Stream<CompletableFuture<Void>> completables;
 CompletableFuture<Void> jointFuture = FutureStreamJoiner.completable().join(completables, concurrencyLimit, executorService);

 Stream<ListenableFuture<Void>> listenables;
 ListenableFuture<Void> jointFuture = FutureStreamJoiner.listenable().join(listenables, concurrencyLimit, executorService);

As this class can't handle a future's result by design, it only accepts futures without result. If the futures in the stream do contain results, the intention to discard those results can be documented by using Futures.toVoidResult(CompletableFuture) or Futures.toVoidResult(ListenableFuture):

 Stream<CompletableFuture<MyPojo>> resultFutures;
 Stream<CompletableFuture<Void>> voidFutures = resultFutures.map(Futures::toVoidResult);
 CompletableFuture<Void> jointFuture = FutureStreamJoiner.completable().join(voidFutures, concurrencyLimit, executorService);

 Stream<ListenableFuture<MyPojo>> resultFutures;
 Stream<ListenableFuture<Void>> voidFutures = resultFutures.map(Futures::toVoidResult);
 CompletableFuture<Void> jointFuture = FutureStreamJoiner.listenable().join(voidFutures, concurrencyLimit, executorService);