HashSet与JDK 7/8的顺序和区别

这是一个两部分问题:

  1. HashSet是否实现了一些隐藏的排序机制,或者只是引用文档: It makes no guarantees as to the iteration order of the set; in particular, it does not guarantee that the order will remain constant over time. It makes no guarantees as to the iteration order of the set; in particular, it does not guarantee that the order will remain constant over time. 告诉我,未来有时可能会改变订单和/或取决于内存使用情况?
  2. 当我在JDK之间切换时,为什么我会得到完全不同的“排序”(我敢说)?

举个例子:

 for (int i = 0; i < 1000; i++) { Set stringSet = new HashSet(); stringSet.add("qwe"); stringSet.add("rtz"); stringSet.add("123"); stringSet.add("qwea"); stringSet.add("12334rasefasd"); stringSet.add("asdxasd"); stringSet.add("arfskt6734"); stringSet.add("123121"); stringSet.add(""); stringSet.add("qwr"); stringSet.add("rtzz"); stringSet.add("1234"); stringSet.add("qwes"); stringSet.add("1234rasefasd"); stringSet.add("asdxasdq"); stringSet.add("arfskt6743"); stringSet.add("123121 "); stringSet.add(" "); System.out.println(stringSet); } 

无论我运行多少次,都会产生以下输出:

JDK 7: [, , 123, qwea, asdxasdq, qwe, qwr, 123121 , arfskt6743, 1234rasefasd, qwes, rtz, rtzz, 1234, 12334rasefasd, asdxasd, arfskt6734, 123121]

JDK 8: [, , qwes, arfskt6743, asdxasdq, 123121, 123121 , arfskt6734, qwr, 123, 1234, qwea, rtzz, rtz, 12334rasefasd, 1234rasefasd, qwe, asdxasd]

显然,空字符串和仅空白字符串两次都是引领方式,但其余部分完全不同。

根据集合更改页面上的更新

7u6中添加的备用String散列函数已从JDK 8中删除,同时还有jdk.map.althashing.threshold系统属性。 相反,包含大量冲突键的哈希箱通过将其条目存储在平衡树而不是链表中来提高性能。 此JDK 8更改仅适用于HashMap,LinkedHashMap和ConcurrentHashMap。

在极少数情况下,此更改可能会引入对HashMap和HashSet的迭代顺序的更改。 没有为HashMap对象指定特定的迭代顺序 – 任何依赖于迭代顺序的代码都应该是固定的。


所以,基本上

用于散列集合的算法已更改以提高性能 。 它变为平衡树而不是链表。

这种更改可能会改变您的集合的迭代顺序 ,并且已确定您应该修复此类行为 ,如果您依赖它。

你看到了一个更好的集合实现,它可能看起来像是有序的,但它纯属巧合。

我建议你不要依赖集的迭代顺序,因为顺序不是保证。

@编辑

如用户Holger所述,另一个概念也很重要,

默认情况下不使用Java 7的“替代字符串散列函数”。 此外,平衡树仅适用于桶冲突场景。 尽管如此,由于这种改进,还有另一个未提及的变化。 对象的哈希码到数组位置的映射经历了从Java 7简化到Java 8的转换

HashSet的内部存储由算法定义。 它不是随机的。

除了基于散列之外,规范(API)没有指定任何特定算法。 实现可以选择它想要的任何算法,并且可以在将来的版本中自由选择不同的算法。

但是,基于算法,​​这意味着对于任何特定版本的实现(Oracle vs IBM,7 vs 8,…),添加一组特定值将始终产生相同的结果,即排序。

对于特定版本的排序是一致的,但它是未定义的,在未来版本和/或不同实现中如有变更,恕不另行通知,因此您不应该依赖订单。

要获得更令人兴奋的内容,请将示例代码更改为

 public static void main(String... args) { System.out.println(System.getProperty("java.version")); List strings=Arrays.asList("qwe", "rtz", "123", "qwea", "12334rasefasd", "asdxasd", "arfskt6734", "123121", "", "qwr", "rtzz", "1234", "qwes", "1234rasefasd", "asdxasdq", "arfskt6743", "123121 ", " "); for (int i = 5; i < 26; i++) { Set stringSet = new HashSet<>(1< 

这仍然以相同的顺序将相同的字符串添加到HashSet ,但是HashSet已经使用不同的容量进行了初始化。
结果是

 1.7.0_51 [, , qwea, 123, asdxasdq, qwe, qwr, 123121 , arfskt6743, 1234rasefasd, qwes, rtzz, rtz, 1234, 12334rasefasd, arfskt6734, asdxasd, 123121] [, qwr, arfskt6743, rtzz, 12334rasefasd, , qwea, 123, asdxasdq, qwe, 123121 , 1234rasefasd, qwes, rtz, 1234, arfskt6734, asdxasd, 123121] [, qwr, arfskt6743, rtzz, 12334rasefasd, , 123, rtz, 1234, arfskt6734, asdxasd, 123121, qwea, asdxasdq, qwe, 123121 , 1234rasefasd, qwes] [, qwr, arfskt6743, rtzz, 12334rasefasd, , arfskt6734, asdxasd, 123121, 123121 , 1234rasefasd, 123, rtz, 1234, qwea, asdxasdq, qwe, qwes] [, rtzz, , 123121, 123121 , 1234rasefasd, 123, rtz, qwea, asdxasdq, qwe, qwes, qwr, arfskt6743, 12334rasefasd, arfskt6734, asdxasd, 1234] [, rtzz, , 123121, 123, asdxasdq, 123121 , 1234rasefasd, rtz, qwea, qwe, qwes, qwr, arfskt6743, 12334rasefasd, arfskt6734, asdxasd, 1234] [, , 123121, asdxasdq, 1234rasefasd, rtz, qwea, qwes, arfskt6743, 12334rasefasd, arfskt6734, asdxasd, rtzz, 123, 123121 , qwe, qwr, 1234] [, , 123121, 1234rasefasd, rtz, qwea, qwes, asdxasd, rtzz, 123, 1234, asdxasdq, arfskt6743, 12334rasefasd, arfskt6734, 123121 , qwe, qwr] [, , rtz, asdxasd, rtzz, arfskt6743, 12334rasefasd, arfskt6734, 123121 , qwe, qwr, 123121, 1234rasefasd, qwea, qwes, 123, 1234, asdxasdq] [, , arfskt6743, 12334rasefasd, arfskt6734, qwea, qwes, 1234, asdxasdq, rtz, asdxasd, rtzz, 123121 , qwe, qwr, 123121, 1234rasefasd, 123] [, , qwea, qwes, rtz, asdxasd, rtzz, 123121 , qwe, qwr, 123, arfskt6743, 12334rasefasd, arfskt6734, 1234, asdxasdq, 123121, 1234rasefasd] [, , qwea, qwes, asdxasd, 1234, asdxasdq, 123121, 1234rasefasd, rtz, rtzz, 123121 , qwe, qwr, 123, arfskt6743, 12334rasefasd, arfskt6734] [, , qwea, qwes, asdxasd, 1234, 1234rasefasd, rtzz, 123121 , 123, arfskt6743, arfskt6734, asdxasdq, 123121, rtz, qwe, qwr, 12334rasefasd] [, , 1234rasefasd, 123, asdxasdq, rtz, qwe, qwr, 12334rasefasd, qwea, qwes, asdxasd, 1234, rtzz, 123121 , arfskt6743, arfskt6734, 123121] [, , 123, asdxasdq, rtz, qwe, qwr, 12334rasefasd, 123121 , 123121, 1234rasefasd, qwea, qwes, asdxasd, 1234, rtzz, arfskt6743, arfskt6734] [, , 123, asdxasdq, rtz, qwe, qwr, 12334rasefasd, 1234rasefasd, qwea, qwes, asdxasd, 1234, rtzz, 123121 , 123121, arfskt6743, arfskt6734] [, , 123, rtz, qwe, qwr, 12334rasefasd, asdxasd, asdxasdq, 1234rasefasd, qwea, qwes, 1234, rtzz, 123121 , 123121, arfskt6743, arfskt6734] [, , 123, rtz, qwe, qwr, asdxasd, asdxasdq, 1234, arfskt6743, arfskt6734, 12334rasefasd, 1234rasefasd, qwea, qwes, rtzz, 123121 , 123121] [, , 123, rtz, qwe, qwr, asdxasdq, 1234, 12334rasefasd, 1234rasefasd, qwea, qwes, rtzz, 123121 , 123121, asdxasd, arfskt6743, arfskt6734] [, , 123, rtz, qwe, qwr, 1234, 12334rasefasd, qwea, qwes, rtzz, 123121 , asdxasdq, 1234rasefasd, 123121, asdxasd, arfskt6743, arfskt6734] [, , 123, rtz, qwe, qwr, 1234, qwea, qwes, rtzz, 12334rasefasd, 123121 , asdxasdq, 1234rasefasd, 123121, asdxasd, arfskt6743, arfskt6734] 
 1.8.0_111 [, , qwes, arfskt6743, asdxasdq, 123121, 123121 , arfskt6734, qwr, 123, 1234, qwea, rtzz, rtz, 12334rasefasd, 1234rasefasd, qwe, asdxasd] [, 123121, arfskt6734, qwr, 1234, asdxasd, , qwes, arfskt6743, asdxasdq, 123121 , 123, qwea, rtzz, rtz, 12334rasefasd, 1234rasefasd, qwe] [, arfskt6734, qwr, , arfskt6743, asdxasdq, 123, rtzz, 123121, 1234, asdxasd, qwes, 123121 , qwea, rtz, 12334rasefasd, 1234rasefasd, qwe] [, qwr, , 123, rtzz, 1234, asdxasd, qwes, 123121 , qwea, rtz, 1234rasefasd, arfskt6734, arfskt6743, asdxasdq, 123121, 12334rasefasd, qwe] [, , 123, 1234, rtz, arfskt6734, arfskt6743, asdxasdq, 123121, 12334rasefasd, qwe, qwr, rtzz, asdxasd, qwes, 123121 , qwea, 1234rasefasd] [, , 1234, asdxasdq, 123121, 12334rasefasd, rtzz, asdxasd, qwes, 123121 , qwea, 123, rtz, arfskt6734, arfskt6743, qwe, qwr, 1234rasefasd] [, , 1234, 12334rasefasd, qwes, qwea, rtz, asdxasdq, 123121, rtzz, asdxasd, 123121 , 123, arfskt6734, arfskt6743, qwe, qwr, 1234rasefasd] [, , asdxasdq, rtzz, 123121 , arfskt6734, arfskt6743, qwe, qwr, 1234, 12334rasefasd, qwes, qwea, rtz, 123121, asdxasd, 123, 1234rasefasd] [, , asdxasdq, 123121 , arfskt6734, arfskt6743, 1234, 12334rasefasd, qwes, qwea, 123121, asdxasd, 1234rasefasd, rtzz, qwe, qwr, rtz, 123] [, , asdxasdq, 1234, rtzz, 123121 , arfskt6734, arfskt6743, 12334rasefasd, qwes, qwea, 123121, asdxasd, 1234rasefasd, qwe, qwr, rtz, 123] [, , 1234, rtzz, 123121 , arfskt6734, arfskt6743, 12334rasefasd, qwes, qwea, 123121, asdxasd, qwe, qwr, rtz, 123, asdxasdq, 1234rasefasd] [, , 1234, 123121 , arfskt6734, arfskt6743, qwes, qwea, asdxasd, rtzz, 12334rasefasd, 123121, qwe, qwr, rtz, 123, asdxasdq, 1234rasefasd] [, , arfskt6734, arfskt6743, asdxasd, 123, asdxasdq, 1234rasefasd, 1234, 123121 , qwes, qwea, rtzz, 12334rasefasd, 123121, qwe, qwr, rtz] [, , arfskt6734, arfskt6743, 123, asdxasdq, 123121 , qwes, qwea, rtzz, 12334rasefasd, 123121, qwe, qwr, rtz, asdxasd, 1234rasefasd, 1234] [, , 123, 123121 , qwe, qwr, rtz, asdxasd, 1234rasefasd, arfskt6734, arfskt6743, asdxasdq, qwes, qwea, rtzz, 12334rasefasd, 123121, 1234] [, , 123, qwe, qwr, rtz, asdxasd, 1234rasefasd, arfskt6734, arfskt6743, qwes, qwea, rtzz, 123121, 1234, 123121 , asdxasdq, 12334rasefasd] [, , 123, qwe, qwr, rtz, arfskt6734, arfskt6743, 123121 , asdxasdq, asdxasd, 1234rasefasd, qwes, qwea, rtzz, 123121, 1234, 12334rasefasd] [, , 123, qwe, qwr, rtz, arfskt6734, arfskt6743, 123121 , 1234, 12334rasefasd, asdxasdq, asdxasd, 1234rasefasd, qwes, qwea, rtzz, 123121] [, , 123, qwe, qwr, rtz, arfskt6734, arfskt6743, 1234, asdxasdq, asdxasd, 1234rasefasd, qwes, qwea, rtzz, 123121 , 12334rasefasd, 123121] [, , 123, qwe, qwr, rtz, 1234, asdxasdq, asdxasd, qwes, qwea, rtzz, 123121 , 12334rasefasd, 123121, arfskt6734, arfskt6743, 1234rasefasd] [, , 123, qwe, qwr, rtz, 1234, qwes, qwea, rtzz, 123121 , 123121, arfskt6734, arfskt6743, asdxasdq, asdxasd, 12334rasefasd, 1234rasefasd] 

这表明迭代顺序不仅取决于特定的实现,还取决于HashSet的历史。 更高的容量也可能是因为之前更大但删除了元素。

虽然哈希码确定要用于元素的arrays位置,但也可能存在冲突,导致元素共享条目。 在该条目中,冲突可能通过链表解析,在这种情况下,此存储桶中的顺序反映了插入顺序,因此它还取决于集合的历史记录,或者可能通过使用自Java 8以来的平衡树来解决,将反映其中一个,哈希码或元素的自然顺序的顺序,具体取决于它是真正的哈希冲突还是只是桶冲突

但是,如果存储桶中存在一定数量的冲突,则Java 8的HashSet将仅使用树,否则,它还使用链接列表。 为了避免在这些变体之间来回切换,它使用不同的阈值来转换为树并转换回链接列表。 因此,如果碰撞的数量在这些阈值之间,它将再次取决于集合的历史,即先前是否存在更多元素,哪些forms以及因此具有哪个顺序。


请注意,默认情况下禁用Java 7的“替代字符串哈希函数”,并且冲突解决方案解决了一个极端情况。 尽管如此,从输出中可以看出,迭代顺序几乎总是存在显着差异。

原因在于,由于现在可以更有效地处理碰撞,因此减少了避免碰撞的尝试。 在Java 7中 ,哈希码在映射到数组位置之前经历了以下转换:

  h ^= (h >>> 20) ^ (h >>> 12); return h ^ (h >>> 7) ^ (h >>> 4); 

相比之下, Java 8使用以下转换:

 return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); 

即使没有发生冲突,这也会对迭代顺序产生直接影响。

答案1:是的Hashset不维护插入顺序,但在此之后如果迭代它,您每次都会得到相同的顺序。

回答2:迭代结果可能与java版本不同,因为它依赖于该版本的哈希码实现。 但是Hashset提供了一个保证,迭代顺序永远不会得到更改意味着在插入元素之后,如果每次在java版本中获得相同的顺序时迭代它。