【问题标题】:Order of element in hashSet [duplicate]hashSet中元素的顺序[重复]
【发布时间】:2015-06-22 17:38:34
【问题描述】:

我在 java 1.7 文档中读到“它不保证集合的迭代顺序”。 这是什么意思?

我创建了一个 HashSet 打印它的元素 1000 次。但每次我得到一个固定的订单。 但是顺序与元素的插入顺序不同。

 Set<String> hashSet = new HashSet<>();

    for (int i = 0; i < 10; i++) {
        hashSet.add("Item+" + i);
    }

    for (String s : hashSet) {
        System.out.println(s);
    }

【问题讨论】:

  • “顺序与元素的插入顺序不同”是您所期望的
  • 因此您收到了无法预测或无法保证的订单。你的问题是?
  • @EJP 我知道我无法预测订单。实际上我期待一个随机订单,但每次我在 java 1.7 上得到一个修复订单。
  • 你为什么期待随机订单?文档没有说顺序是随机的。

标签: java hashset


【解决方案1】:

您应该尝试向集合中添加更多元素(例如,10.000)。 HashSet 的默认容量为 16,但是一旦向集合中添加更多元素,它就会在内部重新构建。在这种情况下,顺序可能会改变。

【讨论】:

  • 订单不是这样的。
  • @erhun 哦,是的。
  • @EJB在我再次阅读之后是的,他是对的,也许答案已被编辑或者我误解了。
【解决方案2】:

这意味着您不能确定顺序是否相同,例如,如果您在另一个 JVM 上运行相同的代码。

你的机器上的顺序总是相同的,使用一个特定的JVM这一事实是无关紧要的。如果顺序很重要,请考虑使用TreeSetTreeSet 将保证顺序始终相同,无论您在何处运行代码。

当然:TreeSet 要求可以以某种方式对项目进行排序(例如按字母顺序)。如果您想保留添加元素的顺序,您可能更喜欢List,例如ArrayList

【讨论】:

  • TreeSet 需要Comparables
  • @SashaSalauyou 正确,正如我所写:它要求可以以某种方式订购物品。对我来说,听起来 OP 想要 List 而不是 Set,但这个问题并不清楚。
  • 我相信 OP 只是将“不可预测的顺序”与“随机顺序”混淆了。
  • 是的,似乎是这样。我刚看到你的回答。它澄清了问题。
【解决方案3】:

HashMap 或 HashSet 中条目的顺序在理论上是可预测的,适用于当前一代和较早的实现。

然而,预测取决于至少

  • 键的哈希值,
  • 集合或地图的初始容量,
  • 在集合/映射中添加和删除键的精确顺序,
  • 所使用的HashSetHashMap 的具体实现(行为取决于Java 版本,并且可能取决于补丁级别),并且
  • 对于 Java 8 及更高版本,密钥是否为 Comparable

如果您掌握了所有这些信息(并且准备好模拟插入/移除顺序),则可以准确预测迭代顺序。但是,实现起来会很棘手,而且运行起来也很昂贵......


在您的示例中,哈希值相同,初始HashSet 容量相同,插入顺序相同,HashSet 实现相同。在这些情况下(并且考虑到使用的精确算法)迭代顺序将是可重复的......即使它很难预测。

在这种情况下,顺序不是“随机的”,因为在构建HashSet 的过程中没有随机性。只是复杂且不透明的计算......但具有确定性。


我在 java 1.7 文档中读到“它不保证集合的迭代顺序”。这是什么意思?

这意味着javadoc没有提交任何特定的行为vis-a-vis排序。当然,我们不承诺便携行为。


另请参阅:Order of values retrieved from a HashMap

【讨论】:

    【解决方案4】:

    在散列集合中,条目按某些内部散列函数的结果排序。

    对于相同集合的条目以相同顺序添加到相同集合,返回顺序将始终相同,尽管哈希函数值也保持相同,除了如果内部结构在调用之间重新组织(即通过扩展或缩小集合) - 在重新组织时,内部散列函数的值将重新计算并且条目在内部散列表中占据另一个位置。

    顺便说一句,哈希集合的条目迭代器只保证您将收到您放在那里但没有被删除的所有条目。

    【讨论】:

    • 这是不正确的。条目顺序还取决于条目被添加到哈希表和从哈希表中删除的顺序,以及它的初始容量。和其他事情。
    • @StephenC 当然,如果您删除然后添加相同的条目,它可以在存储桶中占据另一个位置,并且返回的结果会改变。我更新了我的答案以使其更清楚。
    【解决方案5】:

    也许你可以看到相同的“排序”,但这不是真的,这取决于 JVM,所以,如果你想要一个排序列表

    • 如果您有逻辑排序,请使用 Collections.sort() 或实现您自己的 Comparator

    • 如果您希望按插入顺序对集合进行排序,请使用 ListIterator

      列表迭代器首先保证您以列表的内部顺序(也称为插入顺序)获取列表的元素。更具体地说,它是按照您插入元素的顺序或您操作列表的方式。排序可以看作是对数据结构的一种操作,对列表进行排序有多种方式。

    【讨论】:

      猜你喜欢
      • 2021-07-16
      • 2014-08-28
      • 2015-03-29
      • 2022-07-05
      • 2016-07-25
      • 1970-01-01
      • 2015-07-28
      • 1970-01-01
      • 2020-01-06
      相关资源
      最近更新 更多