我相信有一个很好的理由,但有人能解释一下为什么java.util.Set接口缺少get(int Index),或任何类似的get()方法吗?

集合似乎很适合把东西放进去,但我找不到一种优雅的方法来从中检索单个项目。

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

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

我相信它被排除在API之外的事实意味着有一个很好的理由不这样做——有人能启发我吗?

编辑: 这里有一些非常棒的回答,还有一些说“更多的背景”。具体的场景是一个dbUnit测试,在这个测试中,我可以合理地断言从查询返回的集合只有1个项,并且我正在尝试访问该项。

然而,这个问题在没有场景的情况下更有效,因为它仍然更集中:

set和list的区别是什么?

感谢大家的精彩回答。


当前回答

请注意,只有2个基本的数据结构可以通过索引访问。

数组数据结构可以通过O(1)时间复杂度的索引访问,实现get(int index)操作。 LinkedList数据结构也可以通过索引访问,但要用O(n)时间复杂度来实现get(int index)操作。

在Java中,ArrayList是使用Array数据结构实现的。

而Set数据结构通常可以通过HashTable/HashMap或BalancedTree数据结构实现,为了快速检测元素是否存在并添加不存在的元素,通常一个实现良好的Set可以实现O(1)个时间复杂度包含操作。在Java中,HashSet是Set最常用的实现,它是通过调用HashMap API来实现的,HashMap是使用链表(Array和LinkedList的组合)来实现的。

由于Set可以通过不同的数据结构实现,因此没有get(int index)方法。

其他回答

Set是一个接口,它的一些实现类是HashSet、TreeSet和LinkedHashSet。它在底层使用HashMap来存储值。因为HashMap不保留顺序,所以不可能通过索引获取值。

你现在肯定在想Set是如何使用HashMap的,因为HashMap存储了一个键和值对,而Set没有。有效的问题。当你在Set中添加一个元素时,它在内部维护一个HashMap,其中键是你想在Set中输入的元素,值是虚拟常量。下面是add函数的内部实现。因此,HashMap中的所有键都将具有相同的常量值。

// Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();

public boolean add(E e) {
    return map.put(e, PRESENT)==null;
}

要获取Set中的元素,我使用以下命令:

public T getElement(Set<T> set, T element) {
T result = null;
if (set instanceof TreeSet<?>) {
    T floor = ((TreeSet<T>) set).floor(element);
    if (floor != null && floor.equals(element))
    result = floor;
} else {
    boolean found = false;
    for (Iterator<T> it = set.iterator(); !found && it.hasNext();) {
    if (true) {
        T current = it.next();
        if (current.equals(element)) {
        result = current;
        found = true;
        }
    }
    }
}
return result;
}

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

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

这个“IndexedSet”和SortedSet不一样——在SortedSet中,元素是通过比较器排序的(或者使用它们的“自然”排序)。

但相反,它更接近于LinkedHashSet(其他人也建议),甚至更接近于一个(也不存在)"ArrayListSet",因为它保证元素以插入时相同的顺序返回。

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

因为JDK是开源的,也许这个接口最终会被包含在Java 7中…

根据Set集合的定义,Set中的元素是无序的。所以它们不能被索引访问。

但是为什么我们没有一个get(object)方法,不是通过提供索引作为参数,而是提供一个与我们正在寻找的对象相等的对象? 通过这种方式,我们可以访问Set中元素的数据,只需要知道equal方法使用的属性。

我遇到了这样的情况,我实际上想要一个通过索引访问的SortedSet(我同意其他海报,访问一个没有索引的无序集是没有意义的)。 例如,在树中,我希望对子节点进行排序,不允许重复子节点。

我需要通过索引访问来显示它们,set属性可以有效地消除重复。

在java中找不到合适的集合。util或谷歌集合,我发现它直接实现它自己。基本思想是包装SortedSet并在需要通过索引访问时创建一个List(并且在SortedSet被更改时忘记该列表)。当然,这只有在更改包装的SortedSet和在集合的生命周期中分离访问列表时才有效。否则它就像一个经常排序的列表,也就是说太慢了。

对于大量的子节点,这大大提高了我通过Collections.sort进行排序的列表的性能。