In Java 8, is there a ByteStream class?

2022-08-31 16:54:56

Java 8 provides specializations for , and : , and respectively. However, I could not find an equivalent for in the documentation. Stream<T>doubleintlongDoubleStreamIntStreamLongStreambyte

Does Java 8 provide a class? ByteStream


答案 1

No, it does not exist. Actually, it was explicitly not implemented so as not to clutter the Stream API with tons of classes for every primitive type.

Quoting a mail from Brian Goetz in the OpenJDK mailing list:  

Short answer: no.

It is not worth another 100K+ of JDK footprint each for these forms which are used almost never. And if we added those, someone would demand short, float, or boolean.

Put another way, if people insisted we had all the primitive specializations, we would have no primitive specializations. Which would be worse than the status quo.


答案 2

Most of the byte-related operations are automatically promoted to int. For example, let's consider the simple method which adds a constant to each element of array returning new array (potential candidate for ):bytebyte[]byte[]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 variables, they are widened to and you need to cast the result back to . In Java bytecode most of -related operations (except array load/store and cast to byte) are expressed with 32-bit integer instructions (, , and so on). Thus practically it's ok to process bytes as ints with . We just need two additional operations:byteintbytebyteiaddixorif_icmpleIntStream

  • Create an from array (widening bytes to ints)IntStreambyte[]
  • Collect an to array (using cast)IntStreambyte[](byte)

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 array is more tricky. Using standard JDK classes the simplest solution is :byte[]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 arrays:byte[]

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 , so you can use it like this:IntStream

public static byte[] addStreamEx(byte[] arr, byte addend) {
    return IntStreamEx.of(arr).map(b -> b+addend).toByteArray();
}

Internally method uses simple resizable byte buffer and specially handles the case when the stream is sequential and target size is known in advance.toByteArray()