23

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.

Holger
  • 285,553
  • 42
  • 434
  • 765
drizzt.dourden
  • 683
  • 8
  • 20

6 Answers6

20

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.

Darth Android
  • 3,437
  • 18
  • 19
10

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);
Paul Boddington
  • 37,127
  • 10
  • 65
  • 116
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.

Makoto
  • 104,088
  • 27
  • 192
  • 230
  • Just out of curiosity, can't the OP convert the list into a boolean array afterwards if they really wanted to? – Jeel Shah Apr 08 '16 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 Apr 08 '16 at 21:19
  • Ahhh okay. Thanks for the additional info! – Jeel Shah Apr 08 '16 at 21:21
4

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);
laszlok
  • 2,390
  • 2
  • 17
  • 22
George Mulligan
  • 11,813
  • 6
  • 37
  • 50
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]);
Elliott Frisch
  • 198,278
  • 20
  • 158
  • 249
3

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.

Tagir Valeev
  • 97,161
  • 19
  • 222
  • 334