title: Java CompletableFuture thenCompose with several async tasks
body: <p>I have a process made by 2 async steps. The second steps run based on the result of the first step. The process is launched in a loop. The challenge is that the second step is made by several async tasks taking the output of one first step iteration. As soon as a first step is finished, I would like to launch the n seconds steps using this first step result. I made this piece of code using <code>CompletableFuture</code> and <code>thenCompose</code>.</p>
  
  <p>It works but I find it quite complex and I am wondering if it is the proper way to do it. I am especially wondering if the management of the second level sub-tasks and the use of <code>CompletableFuture.allOf</code> to make it like it is a single <code>CompletableFuture</code> is the proper way of doing.</p>
  
  <pre><code>public void test() {
      // Gather CompletableFutures to wait for them at the end
      List&lt;CompletableFuture&gt; futures = new ArrayList&lt;&gt;();
  
      // First steps
      for (int i = 0; i &lt; 10; i++) {
          int finalI = i;
          CompletableFuture&lt;Void&gt; fut = CompletableFuture.supplyAsync(() -&gt; {
              logger.debug("Start step 1 - " + finalI);
              simulateLongProcessing();// just waits for 1 s
              logger.debug("End step 1 - " + finalI);
              return "step1 output - " + finalI;
          }).thenCompose(s -&gt; {
              List&lt;CompletableFuture&gt; subFutures = new ArrayList&lt;&gt;();
              // Second step : Launch several sub-tasks based on the result of the first step
              for (int j = 0; j &lt; 50; j++) {
                  final int finalJ = j;
                  CompletableFuture&lt;String&gt; f = CompletableFuture.supplyAsync(() -&gt; {
                      logger.debug("Start - step 2 : " + s + " | " + finalJ);
                      simulateLongProcessing();
                      logger.debug("End - step 2 : " + s + " | " + finalJ);
                      return "step2 output - " + s + " | " + finalJ;
                  });
                  subFutures.add(f);
              }
              return CompletableFuture.allOf(subFutures.toArray(new CompletableFuture[0]));
          });
          futures.add(fut);
      }
  
      // Wait for the completion
      for (CompletableFuture future : futures) {
          future.join();
      }
  }
  </code></pre>