Java-8:如何将布尔原始数组转换为流?

50
有没有漂亮的方式可以在Java-8中将给定的boolean[] foo数组转换为流呢?或者我可能遗漏了什么?
提示:Arrays.stream(foo)不能用于boolean[]类型。

3
实际上,Java 8仅为intlongdouble提供了专用的原始流,并且Arrays.stream不接受boolean[]。我想你需要将其装箱。 - Mena
1
在这里,使用 BitSet 而不是使用数组会有好处吗? - JonK
4
@Fildor:是的,你可以在位集上进行流操作。然而,由于你正在对位(即它们的位置编号)进行流处理,因此结果可能会有所不同。令人惊讶的是,障碍在另一方面:没有简洁的方法将boolean[]数组转换为BitSet - Holger
4
希望链接的问答对您有所帮助。创建“BooleanStream”也意味着要创建“PrimitiveIterator.OfBoolean”,“OptionalBoolean”,“BooleanFunction<T>”,“BooleanPredicate”(或者我们滥用“BooleanUnaryFunction”来代替?),“BooleanBinaryOperator”,“BooleanToIntFunction”,“BooleanToLongFunction”,“BooleanToDoubleFunction”,“BooleanConsumer”(由于某种未知原因,“BooleanSupplier”存在),“ObjBooleanConsumer”,“BooleanSummaryStatistics”等。 - Holger
2
@Holger,BooleanSupplier 完成了 (Object|int|long|double|void) -> (Object|int|long|double|void|boolean) 函数矩阵:这 30 个函数实际上都存在于 JDK 中,似乎没有提供其他的一元/零元函数。因此,BooleanSupplier 看起来是合理的选择。 - Tagir Valeev
显示剩余5条评论
4个回答

56

给定boolean[] foo使用

Stream<Boolean> stream = IntStream.range(0, foo.length)
                                  .mapToObj(idx -> foo[idx]);

请注意,每个布尔值都将被装箱,但通常这不是一个大问题,因为对于布尔型的装箱不会分配额外的内存(只使用预定义值之一-Boolean.TRUEBoolean.FALSE)。


2
在您看来,可以推断出“轻量级”布尔运算可能是没有专门的原始流用于布尔的原因吗? - Mena
不错的一个 +1,让我们看看,也许其他想法会浮现在人们的脑海中 :) - Andremoniy
7
@Mena,有多个原因。其中之一是代码膨胀:每个原始流都会增加大量特定的代码,更不用说当你添加 IntStream.mapToBooleanBooleanStream.mapToDouble 等时,API 的增长呈二次函数趋势。所以他们必须在某个地方停下来。他们认为 intlongdouble 是最常用的原始类型,因此这是一个合理的折衷。希望 Java 10 能够为我们带来泛型专门化,使得 Stream<boolean> 可以直接使用。 - Tagir Valeev
3
尽可能接近,我想。但是“好”不同 - 在我看来。 (+1) - Fildor
@TagirValeev 他们本可以停留在...所有的原始类型,因为它们并不多(8种原始类型+1种引用类型)。 - neuralmer

12
你可以使用Guava的Booleans类: Guava的Booleans
Stream<Boolean> stream = Booleans.asList(foo).stream();

这是一种相当高效的方式,因为Booleans.asList返回数组的包装器而不制作任何副本。


1
不错!但请注意,除非定义了自定义分割器(而且它未定义,否则生成的流将不会是SIZED。这可能会影响一些操作(如toArray())的性能。此外,它不会很好地并行化(如果有人关心的话)。 - Tagir Valeev
3
@Tagir Valeev:List 的默认分割器(spliterator)“报告 Spliterator.SIZEDSpliterator.ORDERED”。 - Holger
2
@TagirValeev,我刚刚检查了Booleans.asList()返回的Spliterator的特性,看起来它具有SIZED特性。 - ZhekaKozlov
2
@Holger,抱歉,是我的错。那么唯一的问题就是并行性。虽然这也在Java-9中得到了解决。 - Tagir Valeev
1
@ZhekaKozlov,不对,spliterator的trySplit()方法必须被正确实现。默认情况下是“穷人并行”,它通过迭代器顺序遍历列表到中间缓冲区。 - Tagir Valeev
显示剩余2条评论

2
当然,您可以直接创建一个流。
Stream.Builder<Boolean> builder = Stream.builder();
for (int i = 0; i < foo.length; i++)
  builder.add(foo[i]);
Stream<Boolean> stream = builder.build();

…or by wrapping an AbstractList around foo

Stream<Boolean> stream = new AbstractList<Boolean>() {
  public Boolean get(int index) {return (foo[index]);}
  public int size() {return foo.length;}
}.stream();

这是三个顶级语句 + for 循环内的三个语句表达式。 - Andrey Tyukin
1
@Andrey,我没有其他措辞来表达。直接是指手动逐个组装的意思。我希望您更喜欢第二种解决方案。 - Kaplan

1

浏览最新的早期访问JavaDoc(即java.base模块),仍然没有很好的方法使原始布尔数组与Stream API良好地协作。自以来,API中没有处理原始布尔数组的新功能。

请注意,存在IntStreamDoubleStreamLongStream,但没有像BooleanStream这样的东西,它表示原始布尔序列的变化。此外,Stream的重载方法是Stream::mapToIntStream::mapToDoubleStream::mapToLong,但不是返回假设的BooleanStreamStream::mapToBoolean
Oracle似乎一直遵循这种模式,Collectors中也可以找到。对于float原语类型没有这样的支持(相反,有double原语类型的支持)。在我看来,与float不同,实现boolean支持是有意义的。
回到代码...如果你有一个装箱后的布尔数组(即Boolean[] array),事情会变得更容易:
Boolean[] array = ...
Stream<Boolean> streamOfBoxedBoolean1 = Arrays.stream(array);
Stream<Boolean> streamOfBoxedBoolean2 = Stream.of(array);

否则,你必须像thisthis中所说的那样使用多个语句
然而,你问道(强调我的):
将给定的boolean[] foo数组转换为Java-8中的流的方法是一个语句。
... 实际上有一种方法可以通过使用从Iterator制作的Spliterator来实现一个语句。 这绝对不好看,但是:
boolean[] array = ...

Stream<Boolean> stream = StreamSupport.stream(
        Spliterators.spliteratorUnknownSize(
                new Iterator<>() {
                    int index = 0;
                    @Override public boolean hasNext() { return index < array.length; }
                    @Override public Boolean next() { return array[index++]; }
                }, 0), false);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接