Java Collectors.groupingBy()---List是有序的吗?
Java Collectors.groupingBy()---is List ordered?
对于 Collectors.groupingBy()
returns Map<K,List<T>>
是否暗示 List<T>
是为了评估流?
我没有看到对列表排序的明确描述,而并发版本明确说明没有排序。如果它不是以某种方式订购的,我希望它是 Collection,但我看不出它可能是什么其他订购,除了收到的订单。
我希望它能保证每个列表中的最后一个值是该组收到的最后一个值。
遗憾的是,这个保证没有明确说明。
然而,结果Collector
目前没有UNORDERED
特征,所以实际上,结果List
是有序的。
剩下的问题是,因为没有 API 合同不允许它,未来的版本(或替代实现)是否可以添加该特性并生成无序列表?实际上,即使有充分的理由,OpenJDK 和 Oracle 都极不愿意引入此类重大更改。
在这里,没有理由做出这样的改变;我认为依赖这种行为是安全的。
groupingBy()
的文档说:
Implementation Requirements:
This produces a result similar to:
groupingBy(classifier, toList());
toList()
的文档说:
Returns:
a Collector
which collects all the input elements into a List
, in encounter order
因此,为了回答您的问题,只要您的流具有定义的 encounter order,您就一定会获得有序列表。
编辑:正如@Holger 指出的那样,groupingBy()
还必须遵守相遇顺序以保留toList()
的排序约束。这个注释强烈暗示了它确实存在的事实:
Implementation Note:
...If preservation of the order in which elements are presented to the downstream collector is not required, using groupingByConcurrent(Function, Collector)
may offer better parallel performance.
我做了一个真实的测试,我用这个命令初始化了一个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
对于 Collectors.groupingBy()
returns Map<K,List<T>>
是否暗示 List<T>
是为了评估流?
我没有看到对列表排序的明确描述,而并发版本明确说明没有排序。如果它不是以某种方式订购的,我希望它是 Collection,但我看不出它可能是什么其他订购,除了收到的订单。
我希望它能保证每个列表中的最后一个值是该组收到的最后一个值。
遗憾的是,这个保证没有明确说明。
然而,结果Collector
目前没有UNORDERED
特征,所以实际上,结果List
是有序的。
剩下的问题是,因为没有 API 合同不允许它,未来的版本(或替代实现)是否可以添加该特性并生成无序列表?实际上,即使有充分的理由,OpenJDK 和 Oracle 都极不愿意引入此类重大更改。
在这里,没有理由做出这样的改变;我认为依赖这种行为是安全的。
groupingBy()
的文档说:
Implementation Requirements:
This produces a result similar to:
groupingBy(classifier, toList());
toList()
的文档说:
Returns:
a
Collector
which collects all the input elements into aList
, in encounter order
因此,为了回答您的问题,只要您的流具有定义的 encounter order,您就一定会获得有序列表。
编辑:正如@Holger 指出的那样,groupingBy()
还必须遵守相遇顺序以保留toList()
的排序约束。这个注释强烈暗示了它确实存在的事实:
Implementation Note:
...If preservation of the order in which elements are presented to the downstream collector is not required, using
groupingByConcurrent(Function, Collector)
may offer better parallel performance.
我做了一个真实的测试,我用这个命令初始化了一个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