MoreFutures { public static <V> CompletableFuture<List<V>> allAsList(List<CompletableFuture<? extends V>> futures) { CompletableFuture<Void> allDoneFuture = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])); for (CompletableFuture<? extends V> future : futures) { future.whenComplete((v, throwable) -> { if (throwable != null) { allDoneFuture.completeExceptionally(throwable); } }); } return unmodifiableFuture(allDoneFuture.thenApply(v -> futures.stream(). map(CompletableFuture::join). collect(Collectors.toList()))); } private  MoreFutures(); static void propagateCancellation(ListenableFuture<? extends X> source, Future<? extends Y> destination, boolean mayInterruptIfRunning); static void mirror(ListenableFuture<? extends T> source, SettableFuture<? super T> destination, boolean mayInterruptIfRunning); static Throwable unwrapCompletionException(Throwable throwable); static CompletableFuture<V> unmodifiableFuture(CompletableFuture<V> future); static CompletableFuture<V> unmodifiableFuture(CompletableFuture<V> future, boolean propagateCancel); static CompletableFuture<V> failedFuture(Throwable throwable); static V getFutureValue(Future<V> future); static V getFutureValue(Future<V> future, Class<E> exceptionType); static Optional<T> tryGetFutureValue(Future<T> future); static Optional<V> tryGetFutureValue(Future<V> future, int timeout, TimeUnit timeUnit); static Optional<V> tryGetFutureValue(Future<V> future, int timeout, TimeUnit timeUnit, Class<E> exceptionType); static T getDone(Future<T> future); static void checkSuccess(Future<?> future, String errorMessage); static ListenableFuture<V> whenAnyComplete(Iterable<? extends ListenableFuture<? extends V>> futures); static ListenableFuture<V> whenAnyCompleteCancelOthers(Iterable<? extends ListenableFuture<? extends V>> futures); static CompletableFuture<V> firstCompletedFuture(Iterable<? extends CompletionStage<? extends V>> futures); static CompletableFuture<V> firstCompletedFuture(Iterable<? extends CompletionStage<? extends V>> futures, boolean propagateCancel); static CompletableFuture<List<V>> allAsList(List<CompletableFuture<? extends V>> futures); static ListenableFuture<T> addTimeout(ListenableFuture<T> future, Callable<T> onTimeout, Duration timeout, ScheduledExecutorService executorService); static CompletableFuture<T> addTimeout(CompletableFuture<T> future, Callable<T> onTimeout, Duration timeout, ScheduledExecutorService executorService); static CompletableFuture<V> toCompletableFuture(ListenableFuture<V> listenableFuture); static ListenableFuture<V> toListenableFuture(CompletableFuture<V> completableFuture); static void addSuccessCallback(ListenableFuture<T> future, Consumer<T> successCallback); static void addSuccessCallback(ListenableFuture<T> future, Runnable successCallback); static void addExceptionCallback(ListenableFuture<T> future, Consumer<Throwable> exceptionCallback); static void addExceptionCallback(ListenableFuture<T> future, Runnable exceptionCallback);  }
@Test public void testEmptyAllAsList() { CompletableFuture<List<Object>> future = allAsList(ImmutableList.of()); assertTrue(future.isDone()); assertFalse(future.isCompletedExceptionally()); assertFalse(future.isCancelled()); assertEquals(future.join(), ImmutableList.of()); }
@Test public void testSingleElementAllAsList() { CompletableFuture<String> element1 = new CompletableFuture<>(); CompletableFuture<List<Object>> future = allAsList(ImmutableList.of(element1)); assertFalse(future.isDone()); assertFalse(future.isCancelled()); element1.complete("a"); assertTrue(future.isDone()); assertFalse(future.isCompletedExceptionally()); assertFalse(future.isCancelled()); assertEquals(future.join(), ImmutableList.of("a")); }
@Test public void testExceptionalSingleElementAllAsList() { CompletableFuture<String> element1 = new CompletableFuture<>(); CompletableFuture<List<Object>> future = allAsList(ImmutableList.of(element1)); assertFalse(future.isDone()); assertFalse(future.isCancelled()); element1.completeExceptionally(new RuntimeException()); assertTrue(future.isDone()); assertTrue(future.isCompletedExceptionally()); assertFalse(future.isCancelled()); }
@Test public void testMultipleElementAllAsList() { CompletableFuture<String> element1 = new CompletableFuture<>(); CompletableFuture<String> element2 = new CompletableFuture<>(); CompletableFuture<List<Object>> future = allAsList(ImmutableList.of(element1, element2)); assertFalse(future.isDone()); assertFalse(future.isCancelled()); element1.complete("a"); assertFalse(future.isDone()); assertFalse(future.isCompletedExceptionally()); assertFalse(future.isCancelled()); element2.complete("b"); assertTrue(future.isDone()); assertFalse(future.isCompletedExceptionally()); assertFalse(future.isCancelled()); assertEquals(future.join(), ImmutableList.of("a", "b")); }
@Test public void testExceptionalMultipleElementAllAsList() { CompletableFuture<String> element1 = new CompletableFuture<>(); CompletableFuture<String> element2 = new CompletableFuture<>(); CompletableFuture<List<Object>> future = allAsList(ImmutableList.of(element1, element2)); assertFalse(future.isDone()); assertFalse(future.isCompletedExceptionally()); assertFalse(future.isCancelled()); element1.completeExceptionally(new RuntimeException()); assertTrue(future.isDone()); assertTrue(future.isCompletedExceptionally()); assertFalse(future.isCancelled()); }
@Test(expectedExceptions = UnsupportedOperationException.class) public void testUnmodifiableAllAsList() { CompletableFuture<List<Object>> future = allAsList(ImmutableList.of(new CompletableFuture<String>())); future.complete(null); }