Java中集合元素的顺序问题

7

如果我从同一组数据中创建两个列表,我可以确定这两个列表具有相同的顺序吗?(只要这两个列表具有相同的顺序且我在创建两个列表之间没有对该组数据进行任何操作即可,我不关心顺序)

List l = new ArrayList(set);

List l1 = new ArrayList(set);

我理解到有保证的方法可以创建这些列表并确保其顺序不变,因此没有必要用这种方式创建两个列表。但我想知道,如果在集合中没有执行修改操作,为什么元素的排序会改变。
编辑:该集合是无序HashSet。

1
如果它是一个哈希集合,那么如果在中间被改变了(顺序不能保证,但不会在集合未被修改的情况下改变)。如果它是其他任何类型的集合,则其顺序将被定义,因此您可以根据该顺序进行调整。 - Rogue
这完全取决于实现。我可以构想一种实现方式,其中遍历集合会以某种方式改变集合的顺序。虽然可能性很小,但仍有可能发生,并且不能保证不会发生。 - Mad Physicist
1
不保证迭代顺序的稳定性,甚至包括一致性。Set可能会利用访问来整理内部结构,从而在下一次迭代时更改顺序。 - Boris the Spider
@Boris,这并不是Set本身的属性。例如,一些集合(如TreeSetLinkedHashSet)保证迭代顺序。 - ᴇʟᴇvᴀтᴇ
1
@aetheria 它绝对是的:来自JavaDoc for Set - "元素没有特定的顺序返回". 也就是说,Set明确声明它不提供任何保证。谈论具体的实现是完全无关紧要的 - 就像说Set可以被存储在数据库中一样,因为恰好有PersistentSet - Boris the Spider
我完全同意,如果你得到一个任意的Set,就不应该依赖于迭代顺序。我的意思是(严谨地说),一些Set的实现确实保证了迭代顺序。它们仍然是Set,也就是说,确实有保证迭代顺序的SetSet的区别特性在于它不包含重复项。所有的实现都必须遵守这个约束条件。但是实现可以自由地提供关于迭代顺序或持久性的保证。 - ᴇʟᴇvᴀтᴇ
5个回答

9
您可能会在列表ll1中获得相同的顺序。但由于大多数集合是无序的,您不能保证它们的顺序相同。
从技术上讲,您可以编写实现Set接口的代码,每次调用任何方法时都会更改其顺序。这仍将满足接口。
由于在构造函数new ArrayList(Collection)中调用了集合的toArray方法,因此我们可以查看Set#toArray()Javadoc

返回包含此集合中所有元素的数组。如果此集合对其迭代器返回其元素的顺序作出任何保证,则此方法必须按相同顺序返回元素。

Set#iterator()的Javadoc说没有一般性的保证:

返回此集合中的元素的迭代器。元素以无特定顺序返回(除非该集合是某个提供保证的类的实例)。

鉴于此,我强烈建议您不要依赖列表的顺序。


4

根据文档,

public ArrayList(Collection c) 构造包含指定集合元素的列表,并按照集合迭代器返回的顺序排序

因此,迭代顺序是否始终相同实际上取决于Set接口的实现类。

例如,如果使用LinkedHashSet,则迭代顺序是可预测的。


我相当肯定,目前主要实现所提供的集合实现方式都不会违背这一点,但这并不意味着不能有其他的实现方式。 - Mad Physicist
在我的情况下,我正在使用无序哈希集。 - nahzor
1
对于 HashSet,public Iterator<E> iterator() 返回一个迭代器,用于遍历集合中的元素。这些元素没有特定的顺序返回。看起来您不能依赖于这个顺序。 - MaxZoom

0
一种在无序集合(如Set)上强制实施所需(自然或其他)顺序的方法是从给定集合创建一个有序的Set(换句话说,SortedSet)。如果您的集合不太大,并且您只关心可预测的迭代顺序,则可以执行以下操作:
// set = ...
List<? extends Comparable> list = new TreeSet<>(set).stream().collect(Collectors.toList());

这假设集合中的元素是可比较的。或者,您可以在TreeSet构造函数中使用自己的比较器。然而,如果元素本身不可比较,则创建此类比较器可能会存在一些问题。


0

有些结构是保证顺序的,而有些则不是。如果我们提到Java实现的Set接口,那么就没有保证了。很可能ArrayList的构造函数使用了Set的迭代器。因此,两个列表肯定包含相同的元素,但顺序不同。这实际上就是为什么Set使用contains关键字而不是find来检查元素是否存在。

它是子接口,SortedSet,代表按某些标准排序的集合。在Java 6中,有两个标准容器实现了SortedSet。它们是TreeSetConcurrentSkipListSet。 除了SortedSet接口外,还有LinkedHashSet类。它记住元素插入集合的顺序,并以该顺序返回其元素。

-3

这里有一些有趣且不错的答案,我可以提供一个解决方案。

List list = new ArrayList(set);

List secondList = new ArrayList(list);

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