Java中的Set是否保留顺序?

243
Java Set是否保持顺序?一个方法向我返回了一个Set,并且据说数据是有序的,但是在遍历Set时,数据是无序的。是否有更好的方法来管理这个问题?该方法需要更改以返回除Set以外的其他内容吗?

4
如果一个集合是某个类的实例并提供了保证,那么除此之外,集合中的元素不会按任何特定顺序返回。这是一个Java集合类的迭代器方法所说的。原文链接在这里:http://docs.oracle.com/javase/1.4.2/docs/api/java/util/Set.html - keyser
14个回答

356

Set 接口不保证元素的顺序。

它的子接口SortedSet 表示一个根据某些标准排序的集合。在Java 6中,有两个标准容器实现了 SortedSet 。它们是TreeSetConcurrentSkipListSet

除了SortedSet接口外,还有LinkedHashSet类。它会记住插入元素的顺序,并以此顺序返回其元素。


25
另外,由于Java 8中使用了不同的字符串哈希算法,Set和Map默认(未排序)的顺序将发生变化。如果你依赖于未排序的顺序,在Java 8下你的代码行为将会不同。 - rustyx
我知道类不排序是正常的,但我期望的行为是将它们按照引入的顺序保留下来,而不是打乱元素每次聚合时都进行重新排序。你的解决方案也不是最优的,因为那样我将不得不实现一个完整的结构来使它们以与引入时相同的方式排序。 :S - White_King
1
@White_King:集合是一个不包含“插入顺序”概念的数学概念,因此Java接口遵循其惯例是有意义的。有序集合存在,但其顺序由关系(Java中的比较器)指定,再次与集合论中的定义和Java中的定义相匹配。您对它保留插入顺序的期望可能来自于列表,但集合不是列表。 - Konrad Höffner

146

46
“List”并不等同于“Set”(它无法保证成员的唯一性)。 - lmat - Reinstate Monica
13
在许多商业独特的情况下,列表不能仅仅用于保留顺序,而应该使用Set。LinkedHashSet可以维护顺序并存储唯一值。 - gubs

19

许多成员建议使用LinkedHashSet来保留集合的顺序。你可以使用这个实现来包装你的set。

SortedSet 实现可用于排序,但是为了你的目的,请使用LinkedHashSet

同时从文档中得知:

"该实现使其客户端免受 HashSet 提供的未指定、通常混乱的排序,而不会产生 TreeSet 所关联的增加的开销。它可用于生成一个与原始集合具有相同顺序的集合副本,而不管原始集合的实现情况:"

来源: http://docs.oracle.com/javase/6/docs/api/java/util/LinkedHashSet.html


18

Set只是一个接口。为了保留顺序,你需要使用该接口的特定实现以及子接口SortedSet,例如TreeSet或LinkedHashSet。你可以这样包装你的Set:

Set myOrderedSet = new LinkedHashSet(mySet);

8
为了保持顺序,请使用 ListLinkedHashSet

1
应该使用 LinkedHashSet,而不是 Map - Marko Topolnik
我需要一个 Set 而不是 List,我需要一个 Set,它还保留了对象注入的顺序。 - White_King

8

LinkedHashSet是HashSet的有序版本,它通过所有元素维护一个双向链表。当您关心迭代顺序时,请使用此类代替HashSet。


7
这里是Java中可用的标准Set实现的订单特征的快速摘要:
  1. 保留插入顺序:LinkedHashSetCopyOnWriteArraySet(线程安全)
  2. 在集合内部保持有序项目:TreeSetEnumSet(仅适用于枚举)和ConcurrentSkipListSet(线程安全)
  3. 不按任何特定顺序保留项:HashSet(您尝试过的那个)
对于你的具体情况,你可以先对项目进行排序,然后使用1或2中的任何一个(最有可能是LinkedHashSetTreeSet)。或者更高效地,你可以将未排序的数据添加到TreeSet中,它会自动为你进行排序。

3
Set.iterator()的javadoc中可以看出:
返回此集合中元素的迭代器,元素的顺序不作任何保证(除非这个集合是某个提供保证的类的实例)。
正如shuuchan所述,TreeSetSet的一个实现,它有一个保证顺序的特性:
元素按照它们的自然排序或者在创建集合时提供的比较器进行排序,具体取决于使用哪个构造函数。

3

通常情况下,集合不会保留元素的顺序,例如 HashSet 为了快速查找元素。但是你可以尝试使用 LinkedHashSet,它会按照你添加的顺序来保持元素的顺序。


1

这里有两个不同的事情。

  1. 对一个集合中的元素进行排序。我们可以使用SortedSet和类似的实现来完成。
  2. 保持集合中元素的插入顺序。我们可以使用LinkedHashSet和CopyOnWriteArraySet(线程安全)来完成。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接