Collectors.groupingBy()
返回 Map<K,List<T>>
,这是否意味着 List<T>
的顺序与流的评估顺序相同?我没有看到关于列表排序的明确描述,而并发版本明确指出没有排序。如果它没有以某种方式排序,我希望它应该是一个 Collection,除了按接收顺序排列之外,我不知道还有什么其他的排序方式。
我希望保证每个列表中的最后一个值是该组收到的最后一个值。
Collectors.groupingBy()
返回 Map<K,List<T>>
,这是否意味着 List<T>
的顺序与流的评估顺序相同?groupingBy()
的文档中提到:
实现要求:
这会产生类似于以下的结果:
根据
groupingBy(classifier, toList());
toList()
的文档:因此,回答你的问题,只要你的流有定义的遇到次序,就保证得到有序的列表。返回:
一个收集所有输入元素到一个
List
中的Collector
,元素顺序按照遇到次序确定。
编辑:如@Holger指出,为了保持toList()
的排序约束,groupingBy()
也必须遵守遇到顺序。它的实现说明已经明确暗示了这一点:实现注意事项:
...如果不需要保留元素呈现给下游收集器的顺序,使用
groupingByConcurrent(Function, Collector)
可能会提供更好的并行性能。
我进行了一项真实测试,我使用以下顺序初始化了一个ArrayList<TimeBased>
:
{"1", "2019-03-22 10:20:03", "1"},
{"2", "2019-03-22 10:30:03", "2"},
{"2", "2019-03-22 11:20:03", "3"},
{"1", "2019-03-22 11:20:15", "4"},
{"3", "2019-03-22 11:35:03", "5"},
{"2", "2019-03-22 12:20:03", "6"}
尝试对第一列和第二列进行分组,但结果如下:
id birth number
1 Fri Mar 22 10:20:03 CST 2019 1
1 Fri Mar 22 11:20:15 CST 2019 4
2 Fri Mar 22 12:20:03 CST 2019 6
2 Fri Mar 22 11:20:03 CST 2019 3
2 Fri Mar 22 10:30:03 CST 2019 2
3 Fri Mar 22 11:35:03 CST 2019 5
所以,你看到了,顺序是不符合预期的(日期列的顺序混淆)。
在我执行这个操作之后(添加 LinkedList::new):
Map<Integer, Map<Date, List<TimeBased>>> grouped =
timeBasedBeans.stream().collect(groupingBy(TimeBased::getId, groupingBy(TimeBased::getPeriod,
LinkedHashMap::new, toList())));
然后订单就正确了:
id birth number
1 Fri Mar 22 10:20:03 CST 2019 1
1 Fri Mar 22 11:20:15 CST 2019 4
2 Fri Mar 22 10:30:03 CST 2019 2
2 Fri Mar 22 11:20:03 CST 2019 3
2 Fri Mar 22 12:20:03 CST 2019 6
3 Fri Mar 22 11:35:03 CST 2019 5
很遗憾,这个保证没有明确说明。
然而,目前产生的Collector
并没有UNORDERED
特性,因此实际上,产生的List
是有序的。
剩下的问题是,由于没有API合同禁止它,未来版本(或另一种实现)是否可以添加该特性并生成无序列表?在实践中,即使有充分的理由,OpenJDK和Oracle也极不愿意引入此类破坏性变化。
在这里,很少有理由进行这样的更改;我认为依赖这种行为是安全的。
unordered()
来取消排序。 - Brian GoetzsummarizingInt
也不是无序的?这是有原因的吗?那么groupingBy(func, toSet())
呢?我知道,由于当前的实现方式,它仍然是有序的,但我们必须永远禁止实现识别顺序独立性的约定吗? - Holgersorted()
和distinct()
的顺序保留行为,有些人认为这种行为过度了。因此,丢弃排序是必须记录的,否则您将被困在保留排序的状态中。您可能会问:“为什么不总是记录顺序保留?”但是,请考虑另一种情况:如果map()
和toList()
不保留顺序,那就显然是错误的。(例如:strings.stream().map(String::length).collect(toList())
。)因此,我们指定允许的偏差。 - Brian GoetzsummarizingInt
的文档不允许其实现无序。想一想,这一定是一个疏忽,特别是对于summarizingDouble
,因为它由DoubleSummaryStatistics
支持,而该类明确拒绝排序保证... - HolgersummingDouble()
方法确实有一个注释来说明这一点;summarizingDouble
也应该有。 - Brian Goetz