Преобразование объекта [] из булевых в логическое [] с использованием потоков
Я могу сделать преобразование с кодом следующим образом:
Object[] array = (Object[]) message.get(key);
boolean[] result = new boolean[array.length];
for (int i = 0; i < array.length; i++) {
result[i] = (boolean) array[i];
}
Но я думал, что можно сделать то же самое преобразование, используя потоки Java 8. Я начинаю кодировать что-то вроде этого:
boolean[] = Arrays.stream(array)
.map(Boolean.class::cast)
.map(Boolean::booleanValue)
.toArray()
Но этот код не работает. Компилятор говорит
incompatible types: java.lang.Object[] cannot be converted to boolean[]
Я пытаюсь понять, в чем проблема с кодом. Я думаю, что map(Boolean::booleanValue)
вернет поток логических значений, которые я могу собрать с помощью toArray
.
Ответы
Ответ 1
Нет, потому что map(Boolean::booleanValue)
расширяется до
map((Boolean value) -> (Boolean)value.booleanValue());
(обратите внимание на автобоксинг, вставленный компилятором, потому что функция, переданная в map()
, должна вернуть Object
, а не boolean
)
Вот почему потоки Java8 включают целую кучу специализированных классов (IntStream
, LongStream
и DoubleStream
). К сожалению, для boolean
нет специализированного класса потока.
Ответ 2
Если вы не против идеи получения списка, вы можете просто выполнить collect
в качестве действия вашего терминала:
final List<Boolean> boolList = Arrays.stream(array)
.map(Boolean.class::cast)
.map(Boolean::booleanValue)
.collect(Collectors.toList());
Поток, определенный здесь, способен производить Object[]
только при попытке собрать его в массив. Использование списка по крайней мере позволит вам сохранить тип, в который вы хотите преобразовать его.
Ответ 3
Единственными потоками примитивного типа являются IntStream
, LongStream
и DoubleStream
. В частности, нет BooleanStream
, и нет идиоматического способа преобразования a Stream<Boolean>
в boolean[]
.
Если вам нужна эта функция часто, вы можете использовать служебный класс следующим образом:
public final class BooleanUtils {
private BooleanUtils() {}
public static boolean[] listToArray(List<Boolean> list) {
int length = list.size();
boolean[] arr = new boolean[length];
for (int i = 0; i < length; i++)
arr[i] = list.get(i);
return arr;
}
public static final Collector<Boolean, ?, boolean[]> TO_BOOLEAN_ARRAY
= Collectors.collectingAndThen(Collectors.toList(), BooleanUtils::listToArray);
}
Тогда, учитывая a Stream<Boolean>
, вы сможете:
boolean[] arr = stream.collect(BooleanUtils.TO_BOOLEAN_ARRAY);
Ответ 4
Я думаю, стоит также отметить, что есть toArray(IntFunction<A[]> generator)
, который по крайней мере позволит вам получить окончательный результат Boolean[]
, который ближе к тому, что вы хотели.
Boolean[] boolArray = Arrays.stream(array)
.map(Boolean.class::cast)
.map(Boolean::booleanValue)
.toArray(Boolean[]::new);
Ответ 5
В моей бесплатной библиотеке StreamEx есть коллекционер toBooleanArray
, который создает примитивный булев массив:
boolean[] result = Arrays.stream(array)
.collect(MoreCollectors.toBooleanArray(obj -> (boolean)obj));
Если вам не нравится использование сторонней библиотеки, вы можете реализовать такой сборщик самостоятельно:
public static <T> Collector<T, ?, boolean[]> toBooleanArray(Predicate<? super T> predicate) {
class Acc {
BitSet bs = new BitSet();
int count = 0;
}
return Collector.of(Acc::new, (acc, t) -> acc.bs.set(acc.count++, predicate.test(t)),
(acc1, acc2) -> {
acc2.bs.stream().forEach(i -> acc1.bs.set(i + acc1.count));
acc1.count += acc2.count;
return acc1;
}, acc -> {
boolean[] res = new boolean[acc.count];
acc.bs.stream().forEach(i -> res[i] = true);
return res;
});
}
Он хорошо работает для последовательных и параллельных потоков и вполне совместим с памятью.
Ответ 6
Java-примитивные типы не являются ссылочными типами, поэтому вы не можете напрямую преобразовывать Boolean
в Boolean
(autoboxing and unboxing были добавлены к языку в Java 1.5 и не работают с массивами типов-оболочек для примитивных типов). Однако вы можете использовать IntStream.range(int, int)
, например
boolean[] result = new boolean[array.length];
IntStream.range(0, array.length).forEach(x -> result[x] = (boolean) array[x]);