public static < T > Collector < CompletableFuture < T > , ? , CompletableFuture < List < T > > > toFutureList ( ) { return Collectors . collectingAndThen ( Collectors . < CompletableFuture < T > > toList ( ) , futures -> { AtomicLong resultsRemaining = new AtomicLong ( futures . size ( ) ) ; CompletableFuture < List < T > > result = new CompletableFuture <> ( ) ; BiFunction < T , Throwable , Void > handler = ( success , failure ) -> { if ( failure == null ) { if ( resultsRemaining . decrementAndGet ( ) == 0 ) { result . complete ( futures . stream ( ) . map ( CompletableFutures :: safeGet ) . collect ( toList ( ) ) ) ; } } else { result . completeExceptionally ( failure ) ; } return null ; } ; futures . forEach ( future -> future . handle ( handler ) ) ; return result ; } ) ; }
Collector which converts a stream of CompletableFuture&lt ; T&gt ; into a CompletableFuture&lt ; List&lt ; T&gt ; &gt ;