6

I have an ArrayList of byte[] and I'm wondering if it's possible to convert this to a byte[] using stream from Java 8. All the arrays inside the ArrayList have the same size.

ArrayList<byte[]> buffer = new ArrayList();

byte[] output = buffer.stream(...)
3
  • Concat all the byte[] ? Commented Jul 29, 2017 at 21:37
  • Yes. I want all the bytes in the ArrayList in a unique byte array. Commented Jul 29, 2017 at 21:38
  • 2
    Related: In Java 8, is there a ByteStream class? Commented Jul 29, 2017 at 21:50

4 Answers 4

16

Try this.

List<byte[]> list = Arrays.asList("abc".getBytes(), "def".getBytes());
byte[] result = list.stream()
    .collect(
        () -> new ByteArrayOutputStream(),
        (b, e) -> b.write(e, 0, e.length),
        (a, b) -> {}).toByteArray();
System.out.println(new String(result));
// -> abcdef
Sign up to request clarification or add additional context in comments.

4 Comments

Is this only for API level 24 and above?
@UmairM I don't know "API level 24". But it requires Java 8 or above.
Why is the combiner a no-op? b.writeTo(a); suffices.
When you use b.write(e, 0, e.length), you don’t need to deal with IOException, so the entire lambda expression simplifies to (b, e) -> b.write(e, 0, e.length). Further, I can only second @user167019, don’t write broken combiner functions. Especially when there is a simple straight-forward implementation like b.writeTo(a).
3

This is a possible solution with the Guava library:

List<byte[]> list = Arrays.asList("abc".getBytes(), "def".getBytes());
byte[] res = Bytes.toArray(list.stream()
        .map(byteArray -> Bytes.asList(byteArray))
        .flatMap(listArray -> listArray.stream())
        .collect(Collectors.toList()));

Comments

2

flatMap should be what you are looking for, ideally it should look like this:

byte[] output = buffer.stream().flatMap(x -> Arrays.stream(x)).toArray(n -> new byte[n])

But it does not compile.

With some helper methods:

private Byte[] box(final byte[] arr) {
    final Byte[] res = new Byte[arr.length];
    for (int i = 0; i < arr.length; i++) {
        res[i] = arr[i];
    }
    return res;
}
private byte[] unBox(final Byte[] arr) {
    final byte[] res = new byte[arr.length];
    for (int i = 0; i < arr.length; i++) {
        res[i] = arr[i];
    }
    return res;
}

The following should work (but not very nice or efficient):

byte[] output = unBox(buffer.stream().flatMap(x -> Arrays.stream(box(x))).toArray(n -> new Byte[n]));

3 Comments

Does not compile.
toArray can't be used to output a primitive array (generics don't allow it). This still won't compile.
Updated with a compiling version. (Though I admit it is not very nice.)
2

You can use Guava library, it has Bytes which supports converting byte[] to List<Byte> and back via:

public static List<Byte> asList(byte... backingArray)

and

public static byte[] toArray(Collection<? extends Number> collection)

Another option is to simply iterate and copy the arrays, one by one, to one big byte[], it seems to me simpler and more straightforward that the code in the accepted answer...

public static void main(String[] args) {
    List<byte[]> list = Arrays.asList("abc".getBytes(), "def".getBytes());
    byte[] flattened= flatByteList(list);
    System.out.println(new String(flattened)); // abcdef
}

private static byte[] flatByteList(List<byte[]> list) {
    int byteArrlength = list.get(0).length;
    byte[] result = new byte[list.size() * byteArrlength]; // since all the arrays have the same size
    for (int i = 0; i < list.size(); i++) {
        byte[] arr = list.get(i);
        for (int j = 0; j < byteArrlength; j++) {
            result[i * byteArrlength + j] = arr[j];
        }
    }
    return result;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.