title: Java 8 stream concatenate log files by prefix
body: <p>I have a list of rolling log files, say:</p>
  
  <pre><code>thread1.2018-04-09.log
  thread1.2018-04-10.log
  thread1.2018-04-11.log
  thread2.2018-04-09.log
  thread2.2018-04-10.log
  thread2.2018-04-11.log
  </code></pre>
  
  <p>I want to concatenate all log files of each thread to process the files as if there was only one file per thread.</p>
  
  <p>I started by parsing all files individually:</p>
  
  <pre><code>Files.newDirectoryStream(Paths.get("path/to/log/folder"),
                      path -&gt; path.toString().endsWith(".log"))
                      .forEach(this::parseLog);
  </code></pre>
  
  <p>And then merged the output by manually checking what thread generated the file. Not optimal...</p>
  
  <p>Can I concatenate the streams of the files with the same prefix directly in the stream operation?</p>
  
  <p><strong>Edit:</strong></p>
  
  <p>Following suggestions in the comments, here is what I came up with:</p>
  
  <pre><code>public class Test {
  
      public static void main(String[] args) {
          new Test().readLogs();
      }
  
      public void readLogs() {
          try (Stream&lt;Path&gt; stream = Files.list(Paths.get("."))
                  .filter(path -&gt; path.toString().endsWith(".log"))) {
  
              Map&lt;String, List&lt;Path&gt;&gt; pathsByThread = stream.collect(Collectors.groupingBy(this::getThreadName));
  
              for (String threadName : pathsByThread.keySet()) {
                  pathsByThread.get(threadName).stream().flatMap(this::readAllLines).forEach(this::parseLogLine);
              }
  
          } catch (IOException e) {
              e.printStackTrace();
          }
      }
  
      private String getThreadName(Path path) {
          int index = path.getFileName().toString().indexOf(".");
  
          return path.getFileName().toString().substring(0, index);
      }
  
      private Stream&lt;String&gt; readAllLines(Path path) {
          try (Stream&lt;String&gt; fileContent = Files.lines(path)) {
              return fileContent;
          } catch (IOException e) {
              e.printStackTrace();
          }
          return null;
      }
  
      private void parseLogLine(String line) {
          // Do something smart
          System.out.println(line);
      }
  }
  </code></pre>
  
  <p>I have a runtime error :</p>
  
  <pre><code>Exception in thread "main" java.lang.IllegalStateException: stream has already been operated upon or closed
  </code></pre>