【问题标题】:Convert a Object[] of booleans to a boolean[] using streams使用流将布尔值的 Object[] 转换为 boolean[]
【发布时间】:2016-07-30 04:25:04
【问题描述】:

我可以使用如下代码进行转换:

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

但是,我认为可以使用 Java 8 流进行相同的转换。我开始编写这样的代码:

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

但是这段代码不起作用。编译器说

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

我试图了解代码有什么问题。我认为map(Boolean::booleanValue) 会返回一个我可以用toArray 收集的布尔值流。

【问题讨论】:

  • 这不起作用,因为Object[]boolean[] 是Java 中不可转换的类型,所以实际上Object[] = boolean[] 也不起作用。
  • .toArray() 这里是通用的,所以 Object[] 是你能做到的最好的。您可以编写自己的收集器返回boolean[]
  • @SashaSalauyou 但是您可以使用toArray(IntFunction&lt;A[]&gt; generator) 返回一个类型化数组。我添加了一个答案作为示例。
  • 这里有一个相关的讨论,为什么原始流仅限于某些类型:stackoverflow.com/questions/22435833/…(例如为什么没有CharStream/BooleanStream/etc。就像有IntStream。 )

标签: java arrays java-stream


【解决方案1】:

不,因为map(Boolean::booleanValue) 扩展为

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

(注意编译器插入的自动装箱,因为传递给map()的函数必须返回Object,而不是boolean

这就是为什么 Java8 流包含一大堆专门的类(IntStreamLongStreamDoubleStream)。遗憾的是,boolean 没有专门的流类。

【讨论】:

    【解决方案2】:

    原始类型的唯一流是IntStreamLongStreamDoubleStream。特别是没有BooleanStream,也没有惯用的方法将Stream&lt;Boolean&gt; 转换为boolean[]

    如果你经常需要这个功能,你可以使用这样的工具类:

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

    然后,给定Stream&lt;Boolean&gt;,您将能够:

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

    【讨论】:

      【解决方案3】:

      如果您不反对获取列表的想法,您可以简单地执行collect 作为您的终端操作:

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

      此处定义的流只有在您尝试将其收集到数组时才能生成Object[]。使用列表至少可以让您保持想要将其转换为的类型。

      【讨论】:

      • 只是出于好奇,如果他们真的想的话,OP 不能在之后将列表转换为布尔数组吗?
      • @JeelShah:是的,但他们可以得到Boolean[],而不是boolean[]。如果 OP 想要 boolean[],他们必须做更多的工作。
      • 啊,好吧。感谢您提供更多信息!
      【解决方案4】:

      我认为同样值得注意的是,有一个toArray(IntFunction&lt;A[]&gt; generator) 至少可以让你得到更接近你想要的Boolean[] 的最终结果。

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

      【讨论】:

        【解决方案5】:

        Java 原始类型不是引用类型,因此您不能直接将 Boolean 转换为 booleanautoboxing and unboxing 已添加到 Java 1.5 中的语言中,并且不适用于包装类型的数组以原始类型)。但是,您可以使用 IntStream.range(int, int) 之类的

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

        【讨论】:

          【解决方案6】:

          在我的免费StreamEx 库中有一个收集器toBooleanArray,它创建了一个原始布尔数组:

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

          如果你不喜欢使用第三方库,你可以自己实现这样的收集器:

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

          它适用于顺序和并行流,并且对内存非常友好。

          【讨论】:

            猜你喜欢
            • 2019-06-11
            • 2019-04-05
            • 2013-07-30
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2019-04-07
            • 2022-01-17
            • 2013-11-30
            相关资源
            最近更新 更多