3

I want an InputStream to a sequence of bytes: 0, 1, 2, ... 255.

I can of course create a new byte[0x100], create a loop of int, fill it with the int values cast to byte (don't get me started on Java's signed byte type), and then form a ByteArrayInputStream from that.

But surely with Java 8 there is a better, more compact, and cleverer way. The trick seems to be generating the array of bytes. I found elsewhere that with int it's as easy as the following:

final int[] values =  IntStream.range(0, 0x100).toArray();

But I need a byte array, and there is no ByteStream. Perhaps there is an IntStream collection function that could collect the int values into a byte[] array? Or something even cleverer?

4
  • Can you clarify whether you're starting from an InputStream or a byte sequence? Your question suggests both. And what form does the source or desired byte sequence take? E.g., is it a byte[], or a Stream<Byte>, or something else? Commented Apr 27, 2016 at 20:46
  • An InputStream that produces a particular sequence is where I want to end, not start. A byte[] seems an obvious means, but feel free to skip the byte array if you have a more direct trick for creating an InputStream. Commented Apr 27, 2016 at 21:32
  • What form does your byte sequence take? Is it the specific sequence {1,2,...,255}? Or is it some type of container of arbitrary bytes? Commented Apr 27, 2016 at 22:08
  • Let's go with 0255 for the sake of argument. Commented Apr 27, 2016 at 22:51

4 Answers 4

1

You could declare the byte[] and then use an IntStream with a forEach to fill it. Something like

byte[] arr = new byte[256];
IntStream.range(0, arr.length).forEach(x -> arr[x] = (byte) x);
Sign up to request clarification or add additional context in comments.

Comments

0

A loop would be faster, but if you are asking for the sake of discussion how you might solve it with streams, you could do this, with a little help from the guava Bytes api:

byte[] bytes = IntStream.range(0, 0x100)
    .mapToObj(i -> (byte) i)                        // boxes into a Byte
    .collect(Collectors.collectingAndThen(Collectors.toList(), Bytes::toArray))

In this example, each int is wrapped in a Byte, which are collected to a List and then converted to a byte[].

The advantage of this approach is that it works without knowing the size of the destination array in advance. If you know the size of the array, @ElliotFrisch's answer would be more efficient, and a loop more efficient still.

Comments

0

It's too bad that there isn't a byte version of Arrays.setAll. It would have worked like this:

byte[] foo = new byte[0x100];
setAll(foo, i -> i++);

If someone really wanted it though, they could use this, adapted from the int version of Arrays.setAll:

public static void setAll(byte[] array, IntUnaryOperator generator) {
    Objects.requireNonNull(generator);
    for (int i = 0; i < array.length; i++)
        array[i] = (byte)generator.applyAsInt(i);
}

Comments

0

If you want to create lazy InputStream from an IntStream (using least significant bytes only), you may try this:

public static InputStream asByteInputStream(IntStream is) {
    Spliterator.OfInt spltr = is.spliterator();
    return new InputStream() {
        private int last;

        @Override
        public int read() {
            return spltr.tryAdvance((int val) -> last = val) ? (last & 0xFF) : -1;
        }

        @Override
        public void close() {
            is.close();
        }
    };
}

Usage tests:

AtomicBoolean flag = new AtomicBoolean(false);
InputStream is = asByteInputStream(IntStream.range(0, 256).onClose(() -> flag.set(true)));
byte[] data = new byte[256];
assertEquals(2, is.skip(2));
// read 3..255 into data[0..253]
assertEquals(254, is.read(data));
// nothing more in the input
assertEquals(-1, is.read());
for(int i=0; i<254; i++) {
    assertEquals((byte)(i+2), data[i]);
}
assertEquals(0, data[254]);
assertEquals(0, data[255]);

// close is forwarded to original IntStream
assertFalse(flag.get());
is.close();
assertTrue(flag.get());

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.