49

There is no nice way to convert given boolean[] foo array into stream in Java-8 in one statement, or I am missing something?

(I will not ask why?, but it is really incomprehensible: why not add stream support for all primitive types?)

Hint: Arrays.stream(foo) will not work, there is no such method for boolean[] type.

Andremoniy
  • 34,031
  • 20
  • 135
  • 241
  • 3
    Indeed, Java 8 only provides specialized primitive streams for `int`, `long` and `double`, and `Arrays.stream` does not accept a `boolean[]`. I guess you will have to box it. – Mena Feb 14 '17 at 11:33
  • 1
    Would using a [`BitSet`](http://docs.oracle.com/javase/8/docs/api/java/util/BitSet.html) be of benefit here instead of using an array? – JonK Feb 14 '17 at 11:36
  • 1
    @JonK I think the point is to be able to do stream-operations on it. Can you do that on BitSet? – Fildor Feb 14 '17 at 11:38
  • 1
    @Fildor Yes you can - but because I don't know exactly what the OP is trying to do I couldn't say if a BitSet would be better suited here. I just left it there as a possible alternative and the OP can decide whether or not it would actually be useful – JonK Feb 14 '17 at 11:40
  • 4
    @Fildor: yes, you can do stream operations on a bit set. The result, however, might be different, as you are streaming over the bits (i.e. their positional number) then. Surprisingly, the obstacles are on the other side: there is no concise way to convert a `boolean[]` array to a `BitSet`. – Holger Feb 14 '17 at 11:42
  • @Holger Over the posNumber - of course! Didn't think of that. Moving around in C# world _and_ Java, Java Streams still give me headaches ... – Fildor Feb 14 '17 at 11:44
  • 4
    Hope, that linked Q&A still helps. Creating `BooleanStream` would also imply the creation of `PrimitiveIterator.OfBoolean`, `OptionalBoolean`, `BooleanFunction`, `BooleanPredicate` (or do we abuse `BooleanUnaryFunction` for that?), `BooleanBinaryOperator`, `BooleanToIntFunction`, `BooleanToLongFunction`, `BooleanToDoubleFunction`, `BooleanConsumer`, (for some unknown reason, `BooleanSupplier` exists), `ObjBooleanConsumer`, `BooleanSummaryStatistics`, etc. – Holger Feb 14 '17 at 12:03
  • 2
    @Holger, BooleanSupplier completes the matrix of `(Object|int|long|double|void) -> (Object|int|long|double|void|boolean)` functions: all 30 of these actually exist in JDK, and no other one/zero argument functions seems to be provided. So `BooleanSupplier` looks reasonable. – Tagir Valeev Feb 15 '17 at 04:28
  • @Tagir Valeev: that’s not convincing, as this kind of matrix is arbitrary, i.e. there is no `boolean` on the input side, because all other types producing a `boolean` are predicates, which `BooleanSupplier` is not. When it comes to types like `ObjIntConsumer`, there is no symmetry either. Their existence is much better explained by the fact, that they are actually needed by the provided API. In contrast, the type `BooleanSupplier` is not used at all. – Holger Feb 15 '17 at 12:16

4 Answers4

55

Given boolean[] foo use

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

Note that every boolean value will be boxed, but it's usually not a big problem as boxing for boolean does not allocate additional memory (just uses one of predefined values - Boolean.TRUE or Boolean.FALSE).

Tagir Valeev
  • 97,161
  • 19
  • 222
  • 334
  • 2
    In your opinion, would it be safe to infer that the "lightweight" boxing operations on `boolean`s may be the reason why there are no specialized primitive streams for `boolean`s? – Mena Feb 14 '17 at 11:35
  • Nice one +1, let's see, may be other ideas will come into people minds :) – Andremoniy Feb 14 '17 at 11:35
  • 7
    @Mena, there are multiple reasons. One of them is code blow-up: every primitive stream adds a big amount of specialized code, not to mention quadratic API grow when you add `IntStream.mapToBoolean`, `BooleanStream.mapToDouble` and so on. So they had to stop somewhere. They considered that `int`, `long` and `double` are the most useful primitive types, so it was a reasonable tradeoff. Hopefully Java 10 will bring us generic specialization and `Stream` will work out of the box. – Tagir Valeev Feb 14 '17 at 11:39
  • 3
    Close as you can get, I guess. But "nice" is different - IMHO. (+1) – Fildor Feb 14 '17 at 11:39
  • @TagirValeev They could have stopped at ... all of the primitives, there aren't that many (8 primitives + 1 for references). – neuralmer Oct 02 '20 at 13:56
12

You can use Guava's Booleans class:

Stream<Boolean> stream = Booleans.asList(foo).stream();

This is a pretty efficient way because Booleans.asList returns a wrapper for the array and does not make any copies.

ZhekaKozlov
  • 36,558
  • 20
  • 126
  • 155
  • 1
    Nice! Note though that the resulting stream will not be SIZED unless custom spliterator is defined (and it's [not defined](https://github.com/google/guava/blob/0fd20594150e5493138e83462b25b81db2507f49/guava/src/com/google/common/primitives/Booleans.java#L382). This might impact the performance of some operations like `toArray()`. Also it will not parallelize great (if somebody cares). – Tagir Valeev Feb 14 '17 at 11:50
  • 3
    @Tagir Valeev: the [default spliterator of `List`](https://docs.oracle.com/javase/8/docs/api/java/util/List.html#spliterator--) “reports Spliterator.SIZED and Spliterator.ORDERED”… – Holger Feb 14 '17 at 11:54
  • 2
    @TagirValeev I've just checked the characteristics of the spliterator returned by `Booleans.asList()` and it looks like it has a SIZED charateristic. – ZhekaKozlov Feb 14 '17 at 11:55
  • 2
    @Holger, sorry, my bad. Then the only problem is parallelism. Though it's also [addressed](https://bugs.openjdk.java.net/browse/JDK-8158365) in Java-9. – Tagir Valeev Feb 14 '17 at 11:58
  • @TagirValeev What is the problem with parallelism? I thought the SIZED characteristic is enough for good parallelism, isn't? – ZhekaKozlov Feb 14 '17 at 12:01
  • 1
    @ZhekaKozlov, nope, spliterator `trySplit()` method must be properly implemented. Default is "poor man parallelism" which traverses list sequentially via iterator into intermediate buffers – Tagir Valeev Feb 14 '17 at 12:02
  • 1
    @Tagir Valeev: funny, we have such a `Spliterator` in our code base for years now, but I’m afraid when Java 9 is released, it will not only be obsolete because there will be an appropriate default spliterator, but also because there is little likelihood to encounter a random access list without custom spliterator anymore. I once thought about a `ListIterator` based improvement for non-random access lists, but who uses them anyway… – Holger Feb 14 '17 at 12:15
2

of course you could create a stream directly

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();
Kaplan
  • 2,572
  • 13
  • 14
  • That's three top-level statements + three statement-expressions inside of the `for`. ,_________, – Andrey Tyukin Mar 04 '21 at 19:19
  • 1
    @Andrey I don't have the phrase to put it another way. *Direct* is meant in the sense of *being put together manually piece by piece*. I hope You like solution two more. – Kaplan Mar 05 '21 at 15:12
1

Skimming through the early access JavaDoc (ie. java.base module) of the newest , there is still no neat way to make the primitive boolean array work with Stream API together well. There is no new feature in the API with treating a primitive boolean array since .

Note that there exist IntStream, DoubleStream and LongStream, but nothing like BooleanStream that would represent of a variation of a sequence of primitive booleans. Also the overloaded methods of Stream are Stream::mapToInt, Stream::mapToDouble and Stream::mapToLong, but not Stream::mapToBoolean returning such hypothetical BooleanStream.

Oracle seems to keep following this pattern, which could be found also in Collectors. There is also no such support for float primitives (there is for double primitives instead). In my opinion, unlike of float, the boolean support would make sense to implement.

Back to the code... if you have a boxed boolean array (ie. Boolean[] array), the things get easier:

Boolean[] array = ...
Stream<Boolean> streamOfBoxedBoolean1 = Arrays.stream(array);
Stream<Boolean> streamOfBoxedBoolean2 = Stream.of(array);

Otherwise you have to use more than one statement as said in this or this answer.

However, you asked (emphasizes mine):

way to convert given boolean[] foo array into stream in Java-8 in one statement.

... there is actually a way to achieve this through one statement using a Spliterator made from an Iterator. It is definetly not nice but :

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);
Nikolas Charalambidis
  • 40,893
  • 16
  • 117
  • 183