为什么Collectors.toList()不能处理原始集合?

(这可能与https://stackoverflow.com/a/30312177/160137有关,但我恐怕还是没有得到它。所以我这样问我的问题,希望它能够得出一个我可以更容易理解的答案。)

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

List 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::new, ArrayList::add, ArrayList::addAll); 

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

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

任何见解将不胜感激。

好吧,让IntStream提供带签名的方法是没有问题的
R collect(Collector collector)执行隐式装箱。 它可以像return boxed().collect(collector);

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

它们仅仅出于性能原因而存在,以提供流操作而不需要拳击开销。 因此,显而易见的设计决定不包括通用Stream接口中已存在的任何操作,因为所有这些操作都可以简单地调用boxed().genericOperation(…)

答案是,您已将相关但不同的想法联系起来 。 它是关于提供一个不接受通用Collectorcollect方法,而是一个像Collector.ofInt这样的原始特化,它可以在没有装箱的情况下收集int值,但是对于产生List的收集器,不可避免地包含盒装值,它不会有任何好处。 在预建的collections家中,只有少数人真的可以避免拳击。 所有这些都是作为原始流的显式终端操作提供的( count()sum()min()max()summaryStatistics() ,…)

这是类/接口数量和潜在性能增益之间的权衡。 对于一般的流,决定是创建IntStreamLongStreamDoubleStream ,但是对于收集器,决定不添加这样的特化。

对于原始类型, List<>是一个额外的次优用法。 因此, toArray被认为足够和充足(=最佳使用)。

 int[] array = IntStream.of(3, 1, 4, 1, 5, 9).toArray(); 
 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::new, ArrayList::add, ArrayList::addAll); 

流是int ,就像将generics方法toList()修复为Integer 。 除了IntStream没有接受收集器的collect()方法,只有3参数方法。