24

I can do the conversion with code like this:

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];
}

But, I was think that is possible to do the same conversion using Java 8 streams. I start to code something like this:

boolean[] =  Arrays.stream(array)
                   .map(Boolean.class::cast)
                   .map(Boolean::booleanValue)
                   .toArray()

But this code doesn't work. Compiler says

incompatible types: java.lang.Object[] cannot be converted to boolean[]

I'm trying to understand what is the problem with the code. I think that map(Boolean::booleanValue) would return a stream of boolean values I can collect with toArray.

4
  • 2
    This will not work because Object[] and boolean[] are types in Java that are not convertible, so actually Object[] = boolean[] will not work either.
    – Jagger
    Commented Apr 8, 2016 at 19:16
  • 2
    .toArray() here is generic, so Object[] is the best you can achieve. You may write your own collector to return boolean[]. Commented Apr 8, 2016 at 19:18
  • @SashaSalauyou You can however use toArray(IntFunction<A[]> generator) to return a typed array. I added an answer as an example. Commented Apr 8, 2016 at 20:03
  • There's a related discussion here, for why the primitive streams are limited to only certain types: stackoverflow.com/questions/22435833/… (Why e.g. no CharStream/BooleanStream/etc. like there is IntStream.)
    – Radiodef
    Commented Apr 8, 2016 at 23:57

6 Answers 6

22

No, because map(Boolean::booleanValue) expands to

map((Boolean value) -> (Boolean)value.booleanValue());

(note the autoboxing inserted by the compiler, because the function passed to map() has to return an Object, not a boolean)

This is why the Java8 streams include a whole bunch of specialized classes (IntStream, LongStream, and DoubleStream). Sadly, there is no specialized stream class for boolean.

12

The only streams of primitive type are IntStream, LongStream and DoubleStream. In particular there is no BooleanStream and there is no idiomatic way to convert a Stream<Boolean> to a boolean[].

If you need this functionality frequently you can use a utility class like this:

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);
} 

Then, given a Stream<Boolean>, you will be able to do:

boolean[] arr = stream.collect(BooleanUtils.TO_BOOLEAN_ARRAY);
0
8

If you're not opposed to the idea of getting a list instead, you can simply perform collect as your terminal action:

final List<Boolean> boolList = Arrays.stream(array)
                                     .map(Boolean.class::cast)
                                     .map(Boolean::booleanValue)
                                     .collect(Collectors.toList());

The stream as defined here is only capable of producing an Object[] if you attempt to collect it into an array. Using a list will at least allow you to maintain the type you want to convert it into.

2
  • Just out of curiosity, can't the OP convert the list into a boolean array afterwards if they really wanted to?
    – Jeel Shah
    Commented Apr 8, 2016 at 21:18
  • 2
    @JeelShah: Yes, but they would be able to get a Boolean[], not a boolean[]. If the OP wanted the boolean[] they'd have to do a bit more work.
    – Makoto
    Commented Apr 8, 2016 at 21:19
5

I think it is worth noting too that there is a toArray(IntFunction<A[]> generator) that will at least allow you to have a final result of Boolean[] which is closer to what you wanted.

Boolean[] boolArray =  Arrays.stream(array)
               .map(Boolean.class::cast)
               .toArray(Boolean[]::new);
4

In my free StreamEx library there's a collector toBooleanArray which creates a primitive boolean array:

boolean[] result = Arrays.stream(array)
                         .collect(MoreCollectors.toBooleanArray(obj -> (boolean)obj));

If you don't like using third-party library you can implement such collector by yourself:

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;
            });
}

It works well for sequential and parallel streams and quite memory-friendly.

3

Java primitive types aren't reference types, so you can't do directly convert Boolean to boolean (autoboxing and unboxing were added to the language in Java 1.5 and don't work with arrays of wrapper types to the primitive types). However, you could use an IntStream.range(int, int) like

boolean[] result = new boolean[array.length];
IntStream.range(0, array.length).forEach(x -> result[x] = (boolean) array[x]);

Not the answer you're looking for? Browse other questions tagged or ask your own question.