Most of the byte-related operations are automatically promoted to int. For example, let's consider the simple method which adds a byte
constant to each element of byte[]
array returning new byte[]
array (potential candidate for ByteStream
):
public static byte[] add(byte[] arr, byte addend) {
byte[] result = new byte[arr.length];
int i=0;
for(byte b : arr) {
result[i++] = (byte) (b+addend);
}
return result;
}
See, even though we perform an addition of two byte
variables, they are widened to int
and you need to cast the result back to byte
. In Java bytecode most of byte
-related operations (except array load/store and cast to byte) are expressed with 32-bit integer instructions (iadd
, ixor
, if_icmple
and so on). Thus practically it's ok to process bytes as ints with IntStream
. We just need two additional operations:
- Create an
IntStream
from byte[]
array (widening bytes to ints)
- Collect an
IntStream
to byte[]
array (using (byte)
cast)
The first one is really easy and can be implemented like this:
public static IntStream intStream(byte[] array) {
return IntStream.range(0, array.length).map(idx -> array[idx]);
}
So you may add such static method to your project and be happy.
Collecting the stream into byte[]
array is more tricky. Using standard JDK classes the simplest solution is ByteArrayOutputStream
:
public static byte[] toByteArray(IntStream stream) {
return stream.collect(ByteArrayOutputStream::new, (baos, i) -> baos.write((byte) i),
(baos1, baos2) -> baos1.write(baos2.toByteArray(), 0, baos2.size()))
.toByteArray();
}
However it has unnecessary overhead due to synchronization. Also it would be nice to specially process the streams of known length to reduce the allocations and copying. Nevertheless now you can use the Stream API for byte[]
arrays:
public static byte[] addStream(byte[] arr, byte addend) {
return toByteArray(intStream(arr).map(b -> b+addend));
}
My StreamEx library has both of these operations in the IntStreamEx
class which enhances standard IntStream
, so you can use it like this:
public static byte[] addStreamEx(byte[] arr, byte addend) {
return IntStreamEx.of(arr).map(b -> b+addend).toByteArray();
}
Internally toByteArray()
method uses simple resizable byte buffer and specially handles the case when the stream is sequential and target size is known in advance.