为什么java.util.Set没有get(int index)?

Mar*_*itt 234 java collections set data-structures

我确定这是一个很好的理由,但有人可以解释为什么java.util.Set界面缺乏get(int Index),或任何类似的get()方法?

似乎套装非常适合放入物品,但我找不到从中检索单个物品的优雅方式.

如果我知道我想要第一个项目,我可以使用set.iterator().next(),但是否则我似乎必须转换为数组来检索特定索引处的项目?

从集合中检索数据的适当方法是什么?(除了使用迭代器)

我确信它被排除在API之外意味着有一个很好的理由不这样做 - 有人可以开导我吗?

编辑: 这里有一些非常好的答案,还有一些说"更多背景".特定场景是一个dbUnit测试,我可以合理地断言查询返回的集只有一个项目,我试图访问该项目.

但是,没有这种情况,这个问题更有效,因为它仍然更受关注:

集合和列表之间有什么区别.

感谢所有人在下面的精彩答案.

Mic*_*ers 174

因为套装没有订购.一些实现(特别是那些实现java.util.SortedSet接口的实现),但这不是集合的一般属性.

如果您尝试以这种方式使用集合,则应考虑使用列表.

  • "考虑"是正确的措辞.有两个可能的问题(a)当他应该使用别的东西时,他正在使用一套,或者(b)他试图用他们不支持的集合来做事情,但他可以采取不同的方式.*考虑*这些是哪种情况是好的. (21认同)
  • @matt b:不,我认为他应该考虑一下.思考很好.;) (10认同)
  • 考虑一下,然后去做. (10认同)
  • 可能更简单的答案是使用有序集.(我认为选择集时,唯一性起了作用).但是我有一个问题,因为SortedSet是有序的,为什么api中没有get方法. (6认同)
  • @HDave:不,数据结构的多个实现共享属性的事实不会使它成为数据结构本身的属性.List(ArrayList和Vector)的三种常用实现中的两种是随机访问,但这不会使随机访问成为列表的属性. (5认同)

Sor*_*icu 73

实际上,在编写使用对象关系映射的JavaEE应用程序时(例如使用Hibernate),这是一个反复出现的问题; 来自所有在这里回复的人,Andreas Petersson是唯一理解真正问题并提供正确答案的人:Java缺少UniqueList!(或者您也可以将其称为OrderedSet或IndexedSet).

Maxwing提到了这个用例(你需要有序和唯一的数据),他建议使用SortedSet,但这不是Marty Pitt真正需要的.

此"IndexedSet"与SortedSet不同 - 在SortedSet中,元素使用Comparator(或使用其"自然"排序)进行排序.

但是它更接近LinkedHashSet(其他人也建议),或者更接近于(也是不存在的)"ArrayListSet",因为它保证元素的返回顺序与插入的顺序相同.

但LinkedHashSet是一个实现,而不是一个接口!我们需要的是一个IndexedSet(或ListSet,或OrderedSet,或UniqueList)接口!这将允许程序员指定他需要具有特定顺序且没有重复的元素集合,然后使用任何实现(例如Hibernate提供的实现)对其进行实例化.

由于JDK是开源的,也许这个接口最终将包含在Java 7中......

  • 尽管如此,答案很棒,但在此期间我们又做了什么? (3认同)
  • Apache Commons Collections 有 [`ListOrderedSet`](https://commons.apache.org/proper/commons-collections/apidocs/org/apache/commons/collections4/set/ListOrderedSet.html),这是 OP 需要 7 年的时间以前(我今天需要)。 (3认同)

Jon*_*nik 29

只添加mmyers答案中未提及的一点.

如果我知道我想要第一个项目,我可以使用set.iterator().next(),但是否则我似乎必须转换为一个数组来检索特定索引处的项目?

从集合中检索数据的适当方法是什么?(除了使用迭代器)

您还应该熟悉SortedSet界面(最常见的实现方式TreeSet).

SortedSet是一个Set(即元素是唯一的),它由元素的自然顺序或使用某些元素保持排序Comparator.您可以使用first()last()方法轻松访问第一个和最后一个项目.SortedSet当您需要保持您的收藏品无重复且以某种方式订购时,A 偶尔派上用场.

编辑:如果您需要一个Set,其元素按插入顺序保存(很像列表),请查看LinkedHashSet.


wax*_*ing 25

当你应该使用一个集合以及何时应该使用列表时,这种问题会导致这个问题.通常,建议如下:

  1. 如果您需要订购数据,请使用列表
  2. 如果您需要唯一数据,请使用Set
  3. 如果需要两者,请使用:sortedSet(对于比较器排序的数据)或OrderedSet/UniqueList(对于按插入排序的数据).不幸的是,Java API还没有OrderedSet/UniqueList.

经常出现的第四种情况是你不需要.在这种情况下,您会看到一些程序员使用列表,一些使用集合.就个人而言,我觉得将它设置为无需排序的列表非常有害 - 因为它实际上是另一个野兽.除非你需要设置唯一性或设置相等的东西,否则总是喜欢列表.

  • 如果您是非特定的,请接受Collection <T>或甚至Iterable <T>并初始化为List. (2认同)

ski*_*ppy 17

我不确定是否有人以这种方式拼写出来,但您需要了解以下内容:

集合中没有"第一个"元素.

因为,正如其他人所说,集合没有排序.集合是一种数学概念,具体不包括排序.

当然,您的计算机无法真正保留内存中未排序的内容列表.它必须有一些订购.在内部,它是一个数组或链表或其他东西.但你真的不知道它是什么,它并没有真正的第一个元素; "第一个"出来的元素是偶然出现的,下次可能不是第一个.即使你采取措施"保证"某个特定的第一个元素,它仍然是偶然出现的,因为你恰好正确地实现了一个Set的一个特定实现; 不同的实现可能与您所做的不同.而且,实际上,您可能不会像您认为的那样了解您正在使用的实现.

人们遇到这个ALL.THE.时间.与RDBMS系统并不明白.RDBMS查询返回一组记录.这是与数学相同类型的集合:无序的项目集合,仅在这种情况下,项目是记录.除非你使用ORDER BY子句,否则RDBMS查询结果根本没有保证的顺序,但是人们一直认为这样做然后在某天当数据或代码的形状稍微改变并触发查询优化器工作时自行启动一种不同的方式突然之间,结果并没有按照他们期望的顺序出现.这些通常是那些在数据库类中(或在阅读文档或教程时)没有注意的人,在事先向他们解释时,查询结果没有保证的顺序.


And*_*son 10

标准java集合中缺少一些数据结构.

袋子(像套装但可以多次包含元素)

UniqueList(有序列表,只能包含每个元素一次)

在这种情况下,你似乎需要一个单一的人

如果您需要灵活的数据结构,您可能会对Google Collections感兴趣


小智 7

这是真的,根据Set Collection的定义,Set中的元素没有排序.所以他们无法通过索引访问.

但是为什么我们没有get(object)方法,不是通过提供索引作为参数,而是一个等于我们正在寻找的对象?通过这种方式,我们可以通过了解equ方法使用的属性来访问Set中元素的数据.


for*_*ran 7

如果要按集合中的索引进行大量随机访问,则可以获取其元素的数组视图:

Object[] arrayView = mySet.toArray();
//do whatever you need with arrayView[i]
Run Code Online (Sandbox Code Playgroud)

但有两个主要缺点:

  1. 它不具有内存效率,因为需要创建整个集合的数组.
  2. 如果修改了该集,则视图将过时.


jsi*_*ght 5

这是因为Set仅保证唯一性,但没有提及最佳访问或使用模式.即,Set可以是List或Map,每个都具有非常不同的检索特征.


Hug*_*ugo 5

我可以想到在集合中使用数字索引的唯一原因是迭代.为此,使用

for(A a : set) { 
   visit(a); 
}
Run Code Online (Sandbox Code Playgroud)