【问题标题】:Why doesn't Collectors.toList() work on primitive collections?为什么 Collectors.toList() 不适用于原始集合?
【发布时间】:2016-08-15 23:01:34
【问题描述】:

(这可能与https://stackoverflow.com/a/30312177/160137有关,但我恐怕还是不明白。所以我这样问我的问题,希望它会导致我能更多的答案容易理解。)

通常,当我有一个 Stream 时,我可以使用 Collectors 类中的一种静态方法将其转换为一个集合:

List<String> strings = Stream.of("this", "is", "a", "list", "of", "strings")
    .collect(Collectors.toList());

但是,正如其他人所注意到的,类似的过程不适用于原始流:

IntStream.of(3, 1, 4, 1, 5, 9)
    .collect(Collectors.toList());  // doesn't compile

我可以这样做:

IntStream.of(3, 1, 4, 1, 5, 9)
    .boxed()
    .collect(Collectors.toList());

或者我可以这样做:

IntStream.of(3, 1, 4, 1, 5, 9)
    .collect(ArrayList<Integer>::new, ArrayList::add, ArrayList::addAll);

问题是,为什么 Collectors.toList() 不对原始流执行此操作?是不是没有办法指定包装类型?如果是这样,为什么这也不起作用:

IntStream.of(3, 1, 4, 1, 5, 9)
    .collect(Collectors.toCollection(ArrayList<Integer>::new)); // nope

任何见解将不胜感激。

【问题讨论】:

  • 因为(即使在 Java-8 中),也没有 List&lt;int&gt;。原始类型不是 Object(s)。
  • 签名中的泛型根本不适用于原始类型。就这么简单。
  • 显式调用boxed() 和允许原始流上的盒装收集器在功能上没有区别。如果您问为什么为了方便而不允许这样做,也许设计师想让拳击变得显而易见。
  • @ElliottFrisch,Dici 我认为 OP 明白这一点。问题是为什么不能在原始流上使用盒装收集器?例如,IntStream 可能会接受 Collector&lt;? super Integer, A, R&gt;
  • @shmosel 我想知道编译器是否甚至允许您所谓的“盒装收集器”(尽管我不确定您的意思)。他们本可以复制所有收集器以使它们成为原始收集器,但这不是很好

标签: java java-8 collectors


【解决方案1】:

好吧,让IntStream 提供带有签名的方法
&lt;R,A&gt; R collect(Collector&lt;? super Integer,A,R&gt; collector) 执行隐式装箱是没有问题的。它可以像return boxed().collect(collector); 一样简单地实现。

问题是“为什么应该这样做”或反过来:为什么原始流专业化存在?

它们仅出于性能原因而存在,以提供流操作而无需装箱开销。因此,一个明显的设计决定是不包含通用Stream 接口中已经存在的任何操作,因为所有这些您都可以简单地调用boxed().genericOperation(…)

answer, you have linked 提出了一个相关但不同的想法。它是关于提供一个collect 方法,它不接受通用的Collector,而是像Collector.ofInt 这样的原始特化,它可以在没有装箱的情况下收集int 值,但是对于产生List&lt;Integer&gt; 的收集器来说,不可避免地包含装箱的值,它不会有任何好处。 在预制的收藏家中,只有少数真正可以避免拳击。所有这些都作为原始流上的显式终端操作提供(count()sum()min()max()summaryStatistics(),...)

这是类/接口数量与潜在性能增益之间的权衡。在一般流的情况下,决定是创建IntStreamLongStreamDoubleStream,但在收集器的情况下,决定不添加这样的专业化。

【讨论】:

    【解决方案2】:

    对于原始类型List&lt;&gt; 是添加的次优用法。因此toArray 被认为是足够的和足够的(=最佳使用)。

    int[] array = IntStream.of(3, 1, 4, 1, 5, 9).toArray();
    

    【讨论】:

      【解决方案3】:
      IntStream.of(3, 1, 4, 1, 5, 9)
          .collect(Collectors.toList());  // doesn't compile
      

      流是int,泛型方法toList() 假定一个对象。没有匹配。

      IntStream.of(3, 1, 4, 1, 5, 9)
          .boxed()
          .collect(Collectors.toList());
      

      流是Integer,泛型方法toList() 假定一个对象。匹配!

      IntStream.of(3, 1, 4, 1, 5, 9)
          .collect(ArrayList<Integer>::new, ArrayList::add, ArrayList::addAll);
      

      流是int,就像将泛型方法toList() 固定为Integer。除了 IntStream 没有接受收集器的collect() 方法,只有一个 3 参数方法。

      【讨论】:

        猜你喜欢
        • 2021-06-18
        • 2013-06-23
        • 2019-02-25
        • 2023-03-09
        • 2019-04-12
        • 1970-01-01
        • 2014-06-10
        • 2021-04-17
        • 1970-01-01
        相关资源
        最近更新 更多