在Java8中,有没有ByteStreamclass?
In Java 8, is there a ByteStream class?
Java 8 为 double
、int
和 long
提供 Stream<T>
特化:DoubleStream
、IntStream
和 LongStream
分别。但是,我无法在 the documentation 中找到 byte
的等效项。
Java8是否提供ByteStream
class?
不,它不存在。实际上,它没有被明确地实现,以免每个原始类型的 Stream API 被大量的 类 弄乱。
引用 OpenJDK 邮件列表中来自 Brian Goetz 的 a mail:
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.
大多数与字节相关的操作都会自动提升为 int。例如,让我们考虑一个简单的方法,它向 byte[]
数组的每个元素添加一个 byte
常量,返回新的 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;
}
看,即使我们执行了两个 byte
变量的加法,它们被扩大到 int
,您需要将结果转换回 byte
。在 Java 字节码中,大多数 byte
相关操作(数组 load/store 和转换为字节除外)都用 32 位整数指令表示(iadd
、ixor
, if_icmple
等等)。因此实际上可以将字节处理为具有 IntStream
的整数。我们只需要两个额外的操作:
- 从
byte[]
数组创建一个 IntStream
(将字节扩展为整数)
- 收集一个
IntStream
到 byte[]
数组(使用 (byte)
转换)
第一个很简单,可以这样实现:
public static IntStream intStream(byte[] array) {
return IntStream.range(0, array.length).map(idx -> array[idx]);
}
所以你可以将这样的静态方法添加到你的项目中并且很高兴。
将流收集到 byte[]
数组中比较棘手。使用标准 JDK classes 最简单的解决方案是 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();
}
但是由于同步,它有不必要的开销。另外,最好专门处理已知长度的流以减少分配和复制。尽管如此,现在您可以将 Stream API 用于 byte[]
数组:
public static byte[] addStream(byte[] arr, byte addend) {
return toByteArray(intStream(arr).map(b -> b+addend));
}
我的StreamEx library has both of these operations in the IntStreamEx
class增强了标准IntStream
,所以你可以这样使用它:
public static byte[] addStreamEx(byte[] arr, byte addend) {
return IntStreamEx.of(arr).map(b -> b+addend).toByteArray();
}
内部 toByteArray()
方法使用简单的可调整大小 byte buffer and specially handles 当流是连续的并且目标大小事先已知时的情况。
如果您没有 ByteStream,构建一个
Stream.Builder<Byte> builder = Stream.builder();
for( int i = 0; i < array.length; i++ )
builder.add( array[i] );
Stream<Byte> stream = builder.build();
...其中数组可以是 byte[]
或 Byte[]
类型
我喜欢这个解决方案,因为它在运行时从 byte []
,
而不是构建一个集合,然后从一个集合中流式传输。
我相信这一次只对流执行一个字节。
byte [] bytes =_io.readAllBytes(file);
AtomicInteger ai = new AtomicInteger(0);
Stream.generate(() -> bytes[ai.getAndIncrement()]).limit(bytes.length);
然而,由于 AtomicInteger 的同步瓶颈,这非常慢,所以回到命令式循环!
改用com.google.common.primitives.Bytes.asList(byte[]).stream()
。
Java 8 为 double
、int
和 long
提供 Stream<T>
特化:DoubleStream
、IntStream
和 LongStream
分别。但是,我无法在 the documentation 中找到 byte
的等效项。
Java8是否提供ByteStream
class?
不,它不存在。实际上,它没有被明确地实现,以免每个原始类型的 Stream API 被大量的 类 弄乱。
引用 OpenJDK 邮件列表中来自 Brian Goetz 的 a mail:
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.
大多数与字节相关的操作都会自动提升为 int。例如,让我们考虑一个简单的方法,它向 byte[]
数组的每个元素添加一个 byte
常量,返回新的 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;
}
看,即使我们执行了两个 byte
变量的加法,它们被扩大到 int
,您需要将结果转换回 byte
。在 Java 字节码中,大多数 byte
相关操作(数组 load/store 和转换为字节除外)都用 32 位整数指令表示(iadd
、ixor
, if_icmple
等等)。因此实际上可以将字节处理为具有 IntStream
的整数。我们只需要两个额外的操作:
- 从
byte[]
数组创建一个IntStream
(将字节扩展为整数) - 收集一个
IntStream
到byte[]
数组(使用(byte)
转换)
第一个很简单,可以这样实现:
public static IntStream intStream(byte[] array) {
return IntStream.range(0, array.length).map(idx -> array[idx]);
}
所以你可以将这样的静态方法添加到你的项目中并且很高兴。
将流收集到 byte[]
数组中比较棘手。使用标准 JDK classes 最简单的解决方案是 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();
}
但是由于同步,它有不必要的开销。另外,最好专门处理已知长度的流以减少分配和复制。尽管如此,现在您可以将 Stream API 用于 byte[]
数组:
public static byte[] addStream(byte[] arr, byte addend) {
return toByteArray(intStream(arr).map(b -> b+addend));
}
我的StreamEx library has both of these operations in the IntStreamEx
class增强了标准IntStream
,所以你可以这样使用它:
public static byte[] addStreamEx(byte[] arr, byte addend) {
return IntStreamEx.of(arr).map(b -> b+addend).toByteArray();
}
内部 toByteArray()
方法使用简单的可调整大小 byte buffer and specially handles 当流是连续的并且目标大小事先已知时的情况。
如果您没有 ByteStream,构建一个
Stream.Builder<Byte> builder = Stream.builder();
for( int i = 0; i < array.length; i++ )
builder.add( array[i] );
Stream<Byte> stream = builder.build();
...其中数组可以是 byte[]
或 Byte[]
我喜欢这个解决方案,因为它在运行时从 byte []
,
而不是构建一个集合,然后从一个集合中流式传输。
我相信这一次只对流执行一个字节。
byte [] bytes =_io.readAllBytes(file);
AtomicInteger ai = new AtomicInteger(0);
Stream.generate(() -> bytes[ai.getAndIncrement()]).limit(bytes.length);
然而,由于 AtomicInteger 的同步瓶颈,这非常慢,所以回到命令式循环!
改用com.google.common.primitives.Bytes.asList(byte[]).stream()
。