【问题标题】:How to test if a Java iterator always uses the same order (reproducible ordering)?如何测试 Java 迭代器是否始终使用相同的顺序(可重现的顺序)?
【发布时间】:2012-12-19 01:04:42
【问题描述】:

我有一个代码,其中 Set 上的 for-each 循环需要依赖于迭代器总是以相同的顺序返回元素这一事实,例如

for(ParameterObject parameter : parameters) { /* ... */ }

HashSet 返回的迭代器不保证具有此属性,但据记载LinkedHashSet 的迭代器确实具有此属性。所以我的代码使用了LinkedHashSet,一切正常。

但是,我想知道是否可以赋予我的代码检查传递给它的集合是否符合要求。似乎这是不可能的(除了对LinkedHashSet 的直接测试)。 LinkedHashSet 没有实现我可以测试的接口,LinkedHashSet.iterator() 也没有我可以测试的接口。如果有OrderConsistentCollectionOrderConsistentIterator这样的接口就好了。

(我需要这个属性here)。

【问题讨论】:

  • 不幸的是,我认为没有办法在编译或运行时检查此属性。
  • 除了使用instanceof 来测试 Set 实现之外,我没有看到...但是问题是,您为什么要这样做?
  • 如果要保持插入条目的顺序,请使用List。如果您想保持条目的自然顺序,请使用SortedSet
  • 您是否考虑过实现自己的接口,即使它只是一个“标记”接口(即没有方法)?
  • 确实只是一个“标记”界面。我需要这个的原因如下:我的类有一个 getter,它遍历一个集合并将集合中对象的属性组合成一个属性,然后返回。它还有一个设置器,它取消组合参数,遍历集合并将子属性分配给元素。组合的顺序与问题无关,但是,为了使这项工作 getter 和 setter 必须始终使用相同的迭代顺序。

标签: java collections iterator set


【解决方案1】:

'HashSet.iterator 不按任何特定顺序返回'意味着迭代器返回的元素没有像 List 或 LinkedHashSet 中那样排序或排序。但是 HashSet.iterator 将始终以相同的顺序返回元素,而 HashSet 是相同的。

HashSet 迭代器其实是可预测的,看这个

    HashSet set = new HashSet();
    set.add(9);
    set.add(2);
    set.add(5);
    set.add(1);
    System.out.println(set);

我可以预测输出,它将是 1、2、5、9。因为元素是按 hashCode 排序的。

【讨论】:

  • 我不需要预先确定的顺序,但我确实需要迭代器始终使用相同的顺序(只要集合没有改变)。 LinkedHashSet 有这个属性,但我认为我无法检查它。
  • 我同意 HashSet.iterator API 不是很清楚。但我 100% 确定同一个 HashSet 的顺序是相同的。它将遍历其哈希表,其中元素按其 hashCode 排序,并且具有相同 hashCode 的元素被链接。您可以测试它是如何工作的。
  • 谢谢。我只是想使代码安全或通过一行代码指出特定要求(向查看代码的人),而不是“隐式”依赖这一事实......
  • @Christian_Fries 为了消除歧义并提供清晰性(这是您的目标),您仍然应该检查 SortedSet 或 List(如 @Moritz_Petersen 所指出的那样)并使用适当的实现,因为这些接口保证了属性,而不是依赖具体的实现。如果没有,请确保您对您的代码进行了良好的注释(解释您使用特定实现的原因)!
【解决方案2】:

没有办法检查它——但无论如何你都可以确保它,只需将集合复制到具有该属性的集合中即可。 LinkedHashSet 可以解决问题,但如果您只需要迭代,ArrayList 可能会更好地为您服务。

List<Foo> parameters = new ArrayList<>(parametersSet);

现在parameters 将始终返回具有相同排序的迭代器。

也就是说,您可能会接受 Evgeniy Dorofeev 的建议,他指出即使不保证特定顺序的集合通常确实具有稳定的顺序(即使它们不不保证)。例如,HashSet 就是这样做的。实际上,您必须有一个非常时髦的集合,或者采取积极的随机化措施,才能获得稳定的排序。

HashSet 的顺序无法保证,但取决于其元素的哈希码以及它们的插入顺序;他们不想保证任何事情,因为他们不想将自己锁定在任何一种策略中,如果对象的哈希码来自Object.hashCode(),即使这种松散的合同也会产生基本上随机的顺序。他们没有指定具有复杂含义的排序,然后说它可能会发生变化,而是说没有保证。但这是排序的两个因素,如果集合没有被修改,那么这两个因素将在一次迭代到下一次迭代中保持稳定。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2016-07-14
  • 1970-01-01
  • 2019-01-15
  • 2020-01-26
  • 2012-06-30
  • 1970-01-01
  • 2012-08-30
  • 2010-12-25
相关资源
最近更新 更多