title: Why doesn't my thread wait for CompletableFutures to complete with `allOf()`?
body: <p>I'm studying <code>CompletableFuture</code> in Java 1.8 and having trouble trying to understand <code>allOf</code>. It seems the main thread doesn't wait for any <code>CompletableFuture</code> to complete.</p>
  
  <p>See <a href="https://github.com/nurkiewicz/reactive/blob/master/src/test/java/be/more/reactive/S03_AllOf.java" rel="nofollow noreferrer">https://github.com/nurkiewicz/reactive/blob/master/src/test/java/be/more/reactive/S03_AllOf.java</a> for the example I'm testing.</p>
  
  <p>The test job finishes before any result is printed.</p>
  
  <p>There are two (ugly?) ways to circumvent this: 1) set a timeout on the main thread and wait for both to finish. 2) set a <code>.get()</code> at the end and it will become a blocking task.</p>
  
  <p>Why is this?</p>
  
  <p>Code fragment:</p>
  
  <pre><code>package be.more.reactive;
  
  import be.more.reactive.util.BaseTest;
  import org.junit.Test;
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  
  import java.util.concurrent.CompletableFuture;
  
  public class S03_AllOf extends BaseTest {
  
      private static final Logger log = LoggerFactory.getLogger(S03_AllOf.class);
  
      private final CompletableFuture&lt;String&gt; futureResult1 = getFutureQueryResult("1"); //.exceptionally() ??
      private final CompletableFuture&lt;String&gt; futureResult2 = getFutureQueryResult("2");
      private final CompletableFuture&lt;String&gt; futureResult3 = getFutureQueryResult("3");
      private final CompletableFuture&lt;String&gt; futureResult4 = getFutureQueryResult("4");
  
      @Test
      public void allOf() throws Exception {
          final CompletableFuture&lt;Void&gt; futureResult = CompletableFuture.allOf(   //Void ?? I want List&lt;String&gt;
                  futureResult1, futureResult2, futureResult3, futureResult4
          );
  
  //        futureResult.thenAccept((Void vd) -&gt; vd.??)   //no, it won't work
  
          futureResult.thenRun(() -&gt; {
              try {
                  log.debug("Query result 1: '{}'", futureResult1.get());
                  log.debug("Query result 2: '{}'", futureResult2.get());
                  log.debug("Query result 3: '{}'", futureResult3.get());
                  log.debug("Query result 4: '{}'", futureResult4.get());   //a lot of manual work
  
                  log.debug("Now do on complete");    //handling onComplete
              } catch (Exception e) {
                  log.error("", e);
              }
          });
  
      }
  
  }
  </code></pre>
  
  <p>And in BaseTest:</p>
  
  <pre><code>protected CompletableFuture&lt;String&gt; getFutureQueryResult(final String queryId) {
      return CompletableFuture.supplyAsync(
              () -&gt; db.apply(new Query(queryId))
  
      );
  }
  </code></pre>
  
  <p>And in DB.java</p>
  
  <pre><code>package be.more.reactive.db;
  
  import java.util.concurrent.TimeUnit;
  
  import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic;
  import static org.apache.commons.lang3.RandomUtils.nextInt;
  import static org.apache.commons.lang3.RandomUtils.nextLong;
  
  public class DB {
      public String apply(Query query) {
          try {
              TimeUnit.SECONDS.sleep(nextLong(2, 4));
          } catch (InterruptedException e) {
              e.printStackTrace();
          }
          return String.format("%s_%s", randomAlphabetic(nextInt(4, 12)), query.getId());
      }
  }
  </code></pre>