title: Java 8 Parallel downloads with retry if fail
body: <p>I need to download a list of files quickly and efficiently, re-trying 3 times in case of error (adding it to the end of the list).</p>
  <p>I wrote the following code with a basic idea of what I want to achieve:</p>
  <pre><code> List&lt;Download&gt; downloads = new ArrayList&lt;&gt;();
   
   for (int i = 0; i &lt; downloads.size(); ++i) {
      Download download = downloads.get(i);
      try {
          download.start();
      } catch (Exception ex) {
          int attempt = download.getAttempt();
          System.err.println(&quot;Download error. Attempt: &quot; + attempt);
          if (attempt &lt;= 3) {
              downloads.add(download);
          }
      }
   }
   
   System.out.println(&quot;All downloads finished&quot;);
  </code></pre>
  <p>But for efficiency I'd like to run the downloads in parallel, so I've thought of using an <code>ExecutorService</code>. I found and adapted the following code, but I can't retry in case of error:</p>
  <pre><code> List&lt;Download&gt; downloads = new ArrayList&lt;&gt;();
   ExecutorService executor = Executors.newFixedThreadPool(16);
   
   List&lt;CompletableFuture&lt;Path&gt;&gt; downloadTasks = downloads
       .stream()
       .map(download -&gt; CompletableFuture.supplyAsync(() -&gt; {
           try {
              return download.start();
          } catch (IOException ex) {
              System.err.println(&quot;Error: &quot; + ex);
              ex.printStackTrace();
              return null;
          }
       }, executor))
       .collect(Collectors.toList());
  
   executor.shutdown();
   CompletableFuture.allOf(downloadTasks.toArray(new CompletableFuture[downloadTasks.size()])).join();
   executor.shutdownNow();
   System.out.println(&quot;All downloads finished&quot;);
  </code></pre>
  <p>I have been trying, but without success:</p>
  <pre><code> public void start() {
       List&lt;Download&gt; downloads = new ArrayList&lt;&gt;();
       ExecutorService executor = Executors.newFixedThreadPool(16);
       List&lt;CompletableFuture&lt;Path&gt;&gt; downloadTasks = new ArrayList&lt;&gt;();
       
       for (Download download : downloads) {
          addTask(downloadTasks, download);
       }
       
       // Here only wait for the main tasks.
       CompletableFuture.allOf(downloadTasks.toArray(new CompletableFuture[downloadTasks.size()])).join();
       executor.shutdownNow();
   }
   
   private void addTask(List&lt;CompletableFuture&lt;Path&gt;&gt; tasks, Download task) {
       tasks.add(CompletableFuture.supplyAsync(() -&gt; {
           try {
               return task.download();
           } catch (Exception ex) {
               int attempt = task.getAttemptsCount();
               System.err.println(&quot;Download error (&quot; + attempt + &quot;): &quot; + ex);
               if (attempt &lt; 3) addTask(tasks, task);
               return null;
           }
       }));
   }
  </code></pre>
  <p><strong>Some extra information:</strong></p>
  <p>*I am using Java 8 and the download list can contain up to 100 files...</p>
  <p>*I was also reading about the use of <code>Fork/Join</code> but they say it is not intended for this kind of problem...</p>
  <p>*I need it to be fast and efficient, so I accept any suggestion and modification.</p>