title: Java 8 - Most effective way to merge List<byte[]> to byte[]
body: <p>I have a library that returns some binary data as list of binary arrays. Those byte[] need to be merged into an InputStream.  </p>
  
  <p>This is my current implementation:</p>
  
  <pre><code>public static InputStream foo(List&lt;byte[]&gt; binary) {
      byte[] streamArray = null;
      binary.forEach(bin -&gt; {
          org.apache.commons.lang.ArrayUtils.addAll(streamArray, bin);
      });
      return new ByteArrayInputStream(streamArray);
  }
  </code></pre>
  
  <p>but this is quite cpu intense. Is there a better way?</p>
  
  <p>Thanks for all the answers. I did a performance test. Those are my results:</p>
  
  <ul>
  <li>Function: 'NicolasFilotto' => 68,04 ms average on 100 calls</li>
  <li>Function: 'NicolasFilottoEstSize' => 65,24 ms average on 100 calls</li>
  <li>Function: 'NicolasFilottoSequenceInputStream' => 63,09 ms average on 100 calls</li>
  <li>Function: 'Saka1029_1' => 63,06 ms average on 100 calls</li>
  <li>Function: 'Saka1029_2' => 0,79 ms average on 100 calls</li>
  <li>Function: 'Coco' => 541,60 ms average on 10 calls</li>
  </ul>
  
  <p>I'm not sure if 'Saka1029_2' is measured correctly...</p>
  
  <p>this is the execute function:</p>
  
  <pre><code>private static double execute(Callable&lt;InputStream&gt; funct, int times) throws Exception {
      List&lt;Long&gt; executions = new ArrayList&lt;&gt;(times);
  
      for (int idx = 0; idx &lt; times; idx++) {
          BufferedReader br = null;
          long startTime = System.currentTimeMillis();
          InputStream is = funct.call();
          br = new BufferedReader(new InputStreamReader(is));
          String line = null;
          while ((line = br.readLine()) != null) {}
          executions.add(System.currentTimeMillis() - startTime);
      }
  
      return calculateAverage(executions);
  }
  </code></pre>
  
  <p>note that I read every input stream </p>
  
  <p>those are the used implementations: </p>
  
  <pre><code>public static class NicolasFilotto implements Callable&lt;InputStream&gt; {
  
      private final List&lt;byte[]&gt; binary;
  
      public NicolasFilotto(List&lt;byte[]&gt; binary) {
          this.binary = binary;
      }
  
      @Override
      public InputStream call() throws Exception {
          ByteArrayOutputStream baos = new ByteArrayOutputStream();
          for (byte[] bytes : binary) {
              baos.write(bytes, 0, bytes.length);
          }
          return new ByteArrayInputStream(baos.toByteArray());
      }
  
  }
  
  public static class NicolasFilottoSequenceInputStream implements Callable&lt;InputStream&gt; {
  
      private final List&lt;byte[]&gt; binary;
  
      public NicolasFilottoSequenceInputStream(List&lt;byte[]&gt; binary) {
          this.binary = binary;
      }
  
      @Override
      public InputStream call() throws Exception {
          return new SequenceInputStream(
                  Collections.enumeration(
                          binary.stream().map(ByteArrayInputStream::new).collect(Collectors.toList())));
      }
  
  }
  
  public static class NicolasFilottoEstSize implements Callable&lt;InputStream&gt; {
  
      private final List&lt;byte[]&gt; binary;
      private final int lineSize;
  
      public NicolasFilottoEstSize(List&lt;byte[]&gt; binary, int lineSize) {
          this.binary = binary;
          this.lineSize = lineSize;
      }
  
      @Override
      public InputStream call() throws Exception {
          ByteArrayOutputStream baos = new ByteArrayOutputStream(binary.size() * lineSize);
          for (byte[] bytes : binary) {
              baos.write(bytes, 0, bytes.length);
          }
          return new ByteArrayInputStream(baos.toByteArray());
      }
  
  }
  
  public static class Saka1029_1 implements Callable&lt;InputStream&gt; {
  
      private final List&lt;byte[]&gt; binary;
  
      public Saka1029_1(List&lt;byte[]&gt; binary) {
          this.binary = binary;
      }
  
      @Override
      public InputStream call() throws Exception {
          byte[] all = new byte[binary.stream().mapToInt(a -&gt; a.length).sum()];
          int pos = 0;
          for (byte[] bin : binary) {
              int length = bin.length;
              System.arraycopy(bin, 0, all, pos, length);
              pos += length;
          }
          return new ByteArrayInputStream(all);
      }
  
  }
  
  public static class Saka1029_2 implements Callable&lt;InputStream&gt; {
  
      private final List&lt;byte[]&gt; binary;
  
      public Saka1029_2(List&lt;byte[]&gt; binary) {
          this.binary = binary;
      }
  
      @Override
      public InputStream call() throws Exception {
          int size = binary.size();
          return new InputStream() {
              int i = 0, j = 0;
  
              @Override
              public int read() throws IOException {
                  if (i &gt;= size) return -1;
                  if (j &gt;= binary.get(i).length) {
                      ++i;
                      j = 0;
                  }
                  if (i &gt;= size) return -1;
                  return binary.get(i)[j++];
              }
          };
      }
  
  }
  
  public static class Coco implements Callable&lt;InputStream&gt; {
  
      private final List&lt;byte[]&gt; binary;
  
      public Coco(List&lt;byte[]&gt; binary) {
          this.binary = binary;
      }
  
      @Override
      public InputStream call() throws Exception {
          byte[] streamArray = new byte[0];
          for (byte[] bin : binary) {
              streamArray = org.apache.commons.lang.ArrayUtils.addAll(streamArray, bin);
          }
          return new ByteArrayInputStream(streamArray);
      }
  
  }
  </code></pre>