【问题标题】:Does Java groupingBy collector preserve list order?Java groupingBy 收集器是否保留列表顺序?
【发布时间】:2016-09-12 02:22:21
【问题描述】:

考虑一个列表List<People>,其中元素按People.getAge() 的升序排序。如果我们使用Collectors.groupingBy(People::getCity) 对该列表进行分组,每个组/城市的结果列表是否仍按年龄排序?

实际上,它似乎确实保留了顺序。我正在寻找保证。

该方法的 Javadoc 说:

如果不需要保留元素在生成的 Map 收集器中出现的顺序,则使用 groupingByConcurrent(Function) 可能会提供更好的并行性能

我不确定这是否指的是列表中项目的顺序。

【问题讨论】:

  • 您的 Javadoc 引用非常清楚地说明了这一点。为什么会有疑问?
  • @FrankPuffer:地图收集器是指用于构建地图元素的toList收集器吗?
  • @FrankPuffer:groupingBy 保留了订单,但遗憾的是,Collectors.groupingBy's JavaDoc 并没有说明这样做的任何内容。这很糟糕,因为虽然我们可以查看 OpenJDK 实现或进行实证测试,但它们告诉我们的只是实现当前做了什么,而不是合约是什么。所以希望它在 JDK API 文档中某处得到澄清。
  • @FrankPuffer 引用的部分确实没有。只讲了不需要保存的情况,没有讲需要保存的情况;)
  • @T.J.Crowder, @Mifeet:从严格的逻辑角度来看,你是对的。但是如果groupingBy 不能保证保持秩序,那么引用的句子就没有意义了。 (我不希望标准包的 JavaDoc 中有无意义的陈述。)

标签: java java-stream collectors


【解决方案1】:

理解合同的关键在于它所说的“元素出现的顺序”。它谈论它们是否按顺序到达,这意味着它们是否按顺序传递给密钥提取器Function和任何下游收集器;它没有说明订单是否会保留在任何结果积累中;事实上,groupingBy 的当前实现使用了不保留密钥顺序的 HashMap

你问它是否指的是列表中项目的顺序。如果您指的是创建 Stream 的 List,则在 List 上创建的 Stream 确实开始时是有序的,但是某些流操作会更改顺序或使其无序,因此它所指的 ordering 是指管道后的结果顺序如果流保持有序,则操作完成。如果流操作使流无序,则元素在收集器中出现的顺序不再是问题。

如果您指的是 List 中的项目顺序,分组项目被收集到,是的,它确实如此,因为“元素出现的顺序”是处理元素的顺序。分组到下游收集器时也是如此;如果 Stream 仍然是有序的,并且您分组到保留顺序的下游收集器,这将保留该顺序,而 Concurrent 版本可能不会。

【讨论】:

  • 引用的 Javadoc 是“如果保留元素出现在 resulting 映射中的顺序...”。准确地说,它只是说result中的顺序被保留了,对此可以理解为:给定相同的输入,无论处理多少次,结果的顺序都是一样的。为此,即使 incoming 流中的顺序也没有保留,只要结果一致,它仍然符合 Javadoc 所说的。 (我也相信 Javadoc 的初衷是说保留了与输入相对应的顺序。但是它写得很含糊)
  • 虽然在技术上是模棱两可的,但在这种情况下,“保持顺序”可能是指在输出中保持输入顺序。 “保持秩序”是用来描述这件事的常用短语。
猜你喜欢
  • 2015-06-15
  • 1970-01-01
  • 2011-11-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多