В Java 8 есть класс ByteStream?
Java 8 предоставляет Stream<T>
специализации для double
, int
и long
: DoubleStream
, IntStream
и LongStream
соответственно. Однако я не смог найти эквивалент для byte
в документации.
Предоставляет ли Java 8 класс ByteStream
?
Ответы
Ответ 1
Нет, его не существует. Фактически, он явно не реализован, чтобы не загромождать Stream API с множеством классов для каждого примитивного типа.
Процитировать почту от Брайана Гетца в списке рассылки OpenJDK:
Короткий ответ: нет.
Для этих форм не стоит других 100K + следов JDK которые почти никогда не используются. И если мы добавим их, кто-то запрос короткий, плавающий или логический.
Иными словами, если люди настаивали, что у нас есть все примитивные специализаций, у нас не было бы примитивных специализаций. Который будет хуже, чем статус-кво.
Ответ 2
Большинство операций, связанных с байтом, автоматически повышаются до 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
(за исключением загрузки/хранения массива и байт-байт) выражаются с помощью 32-разрядных целых инструкций (iadd
, ixor
, if_icmple
и т.д.). Таким образом, практически нормально обрабатывать байты как int с IntStream
. Нам просто нужны две дополнительные операции:
- Создайте массив
IntStream
из byte[]
(расширяя байты до int)
- Соберите массив
IntStream
в byte[]
(используя (byte)
cast)
Первый из них очень прост и может быть реализован следующим образом:
public static IntStream intStream(byte[] array) {
return IntStream.range(0, array.length).map(idx -> array[idx]);
}
Итак, вы можете добавить такой статический метод в свой проект и быть счастливым.
Сбор потока в массив byte[]
более сложный. Используя стандартные классы JDK, самым простым решением является 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 библиотеке есть обе эти операции в классе IntStreamEx
, который повышает стандарт IntStream
, поэтому вы можете использовать его следующим образом:
public static byte[] addStreamEx(byte[] arr, byte addend) {
return IntStreamEx.of(arr).map(b -> b+addend).toByteArray();
}
Внутренний метод toByteArray()
использует простой изменяемый размер байтовый буфер и специально обрабатывает случай, когда поток последовательный и целевой размер известен заранее.