5

I have a byte[] and I want to make a byte stream.

For int[] and long and double, I see methods in the Arrays class:

Arrays.stream(int[] array)
Arrays.stream(long[] array)
Arrays.stream(double[] array)

However, I don't see any for a method Arrays.stream(byte[] array).

What then is the easiest and most concise way to then get a stream of byte primitives as actual bytes?

I need to do transformations on byte[]'s and I need a Stream of bytes to do it using all the Stream functions (and no, I don't want to convert them all to ints.)

Who has a nice solution?

PS. Someone else is providing me the byte[] from a microcontroller API ... So I don't want to play with some other data type if not necessary.

Thanks.

The Coordinator
  • 13,007
  • 11
  • 44
  • 73
  • What's wrong with boxing the bytes to a `Stream`? The boxing [is cached](https://docs.oracle.com/javase/8/docs/api/java/lang/Byte.html#valueOf-byte-), so it doesn't cost you anything more than an index lookup. Then you can work with the Bytes using all of the Stream stuff, and Java will auto-unbox and re-box them as needed for you. – yshavit Nov 23 '19 at 02:25
  • @yshavit That's fine. But it requires an intermediate step to create another array and then move the `byte` to a `Byte`. Why not post and answer? Let's see your full solution. – The Coordinator Nov 23 '19 at 02:29
  • 1
    I don't think this is a dupe of [this question](https://stackoverflow.com/questions/32459683/in-java-8-is-there-a-bytestream-class). That question has a narrow scope: yes or no, does a ByteStream exist. This question asks what can be done about it. – yshavit Nov 23 '19 at 02:37
  • 2
    @yshavit I agree. I'm glad it was reopened. – WJS Nov 23 '19 at 02:58
  • Depending on what you want to do with the stream, you could use the old `new DataInputStream(new ByteArrayInputStream(bytes));` instead – boot-and-bonnet Nov 23 '19 at 04:47
  • I need to do Stream operations. The InputStream types do not offer a Stream conversion. – The Coordinator Nov 23 '19 at 07:14

3 Answers3

5

A Stream<Byte> is about as good as a ByteStream of primitives would be, since Byte#valueOf returns cached instances of the boxed values (and the compiler handles boxing and unboxing for you). So then the only trick is to turn your byte[] into a Stream<Byte>.

One way to do that would be to create an IntStream of indexes, and then map those indexes into lookups into your byte[]:

byte[] byteArray = "hello".getBytes();
Stream<Byte> byteStream = IntStream.range(0, byteArray.length)
    .mapToObj(i -> byteArray[i]);

I don't know of any helper method in the JDK that does this for you.

yshavit
  • 42,327
  • 7
  • 87
  • 124
2

You could do something like this.

  byte[] a = { 1, 2, 3, 4
  };
   
  byteStream(a).forEach(System.out::println);


  public static IntStream byteStream(byte[] a) {
     return IntStream.range(0, a.length).map(idx -> a[idx]);
  }

  public static byte[] toByteArray(IntStream b) {
      Byte[] barray = b.mapToObj(a ->(byte)( a & 0xFF)).toArray(Byte[]::new);
      byte[] ret = new byte[barray.length];
      int i = 0;
      for(byte byt : barray) {
          ret[i++] = byt;
      }
  }

Otherwise you may need to use Steam with Byte since the primitive implementations of byte, float, and short don't exist. I believe Guava supports byte streams.

WJS
  • 36,363
  • 4
  • 24
  • 39
  • `IntStream.range(0, a.length).map(idx -> a[idx]);` I like that. It isn't too complicated either! – The Coordinator Nov 23 '19 at 02:32
  • 1
    @TheCoordinator But fair warning. It has it's limitations. It is still an Intstream and there is no easy way to get it back into a primitive byte array. – WJS Nov 23 '19 at 02:35
  • 1
    sadly, this fails with two runtime errors (both `ArrayStoreException`s) - on `toArray(Byte[]::new)` and ( if you provide a correct `Byte[]` in a different way) `arraycopy` which doesn't handle objects (via unboxing) automatically – almondandapricot Sep 15 '22 at 04:12
  • @almondandapricot Yep. I believe it is fixed. Had to alter the mapping and used a for loop to do the copying. – WJS Sep 17 '22 at 02:13
0

You can do it like this

byte[] byteArray = "Hello World".getBytes();

    Stream.Builder<Byte> builder = Stream.builder();
    for (int i = 0; i < byteArray.length; i++) {
        builder.add(byteArray[i]);
    }
    Stream<Byte> stream = builder.build();

    stream.forEach(str -> System.out.print(str + " ")); 

    /*for(Object b : stream.toArray()){
        String a= new String(new byte[]{(byte)b});
        System.out.println(a);
    }*/