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. 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.) 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.

Sign up to request clarification or add additional context in comments.

Comments

13

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

Comments

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 Comments

Just out of curiosity, can't the OP convert the list into a boolean array afterwards if they really wanted to?
@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.
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);

Comments

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.

Comments

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.