我认为这对于不确定应该使用哪种集合的人来说是一个有用的资源,所以我尝试寻找一个类似的Java流程图,但未能找到。
有哪些资源和“备忘单”可帮助人们在编写Java代码时选择正确的集合?人们如何知道应该使用哪些List、Set和Map实现?
由于我找不到类似的流程图,所以决定自己制作一张。
本流程图不尝试涵盖同步访问、线程安全等内容或旧集合,但它确实涵盖了3个标准的Set、3个标准的Map和2个标准的List。
此图片是为了回答而创建的,并获得知识共享署名4.0国际许可证。最简单的归属方式是链接到该问题或该答案。
其他资源
可能最有用的其他参考是来自Oracle文档的以下页面,其中描述了每个Collection。
HashSet vs TreeSet
关于何时使用HashSet
或TreeSet
的详细讨论在这里:
Hashset vs Treeset
ArrayList vs LinkedList
LinkedList
是一个双向链表,因此在开头和结尾的访问都很快。你会注意到,在上面的所有分支中,三个问题都必须回答“是”,我才会建议使用LinkedList
- 换句话说,我同意你的观点,在大多数情况下答案是否定的。像队列和双端队列这样需要不断添加和删除列表末尾元素的情况是LinkedList
的好用例。 - Tim BLinkedList
每个元素使用的内存更多...但是 ArrayList
从不释放内存。这意味着如果您有一个列表,有时会增长到巨大的大小,但通常很小,那么 ArrayList
将提供更差的内存性能。与其包含的元素相比,List
本身的内存开销通常(虽然不总是)很小。 - Tim BMap<K,V>
isn't the part of java.util.collection
- Mehraj MalikCollection
:一个表示无序“包”或称为“元素”的接口。下一个元素是未定义的(随机的)。
Set
:表示没有重复项的Collection
接口。
HashSet
:由Hashtable
支持的Set
。在不考虑排序时具有最快和最小的内存使用情况。LinkedHashSet
:在插入顺序中关联元素的HashSet
。下一个元素是最近插入的元素。TreeSet
:元素由Comparator
(通常是自然排序)排序的Set
。内存使用最慢最大,但对于基于比较器的排序是必要的。EnumSet
:一种极其快速和高效的Set
,专门定制给单个枚举类型使用。List
:表示一个Collection
,其中的元素是有序的,并且每个元素都有一个数字索引表示其位置,其中零是第一个元素,而(length - 1)
是最后一个。
ArrayList
:由数组支持的List
,其中该数组具有至少与元素数量(列表的“大小”)相同的长度(称为“容量”)。当大小超过容量时(添加第(capacity + 1)
个元素时),数组将以新的容量(new length * 1.5)
重新创建--这个过程很快,因为它使用了System.arrayCopy()
。删除、插入/添加元素需要将所有相邻的元素(右侧)移动到该空间中或从该空间中移出。访问任何元素都很快,因为它只需要计算(element-zero-address + desired-index * element-size)
来找到其位置。在大多数情况下,优先使用ArrayList
而非LinkedList
。LinkedList
:一种由一组对象支持的列表,每个对象都连接到其“前一个”和“后一个”邻居。 LinkedList
也是Queue
和 Deque
。访问元素是从第一个或最后一个元素开始,然后遍历,直到达到所需的索引。插入和删除操作,在通过遍历达到所需的索引后,只需要重新映射仅与新元素相邻的链接或绕过现在已经被删除的元素即可。Map
: 表示一个Collection
,其中每个元素都具有一个标识性的“键”——每个元素都是一个键值对。
HashMap
:键是无序的Map
,由Hashtable
支持。LinkedhashMap
:键按插入顺序排序。TreeMap
: 键按Comparator
(通常是自然排序)排序的Map
。 Queue
:表示一种集合,元素通常从一个端添加,从另一个端移除(FIFO:先进先出)。Stack
:表示一种集合,元素通常从同一端添加(推入),并从该端移除(弹出)(LIFO:后进先出)。Deque
:缩写为“双端队列”,通常发音为“deck”。它是一个链表,通常只能从两端添加和读取(而不是中间)。基本集合图示:
将元素插入 ArrayList
和 LinkedList
进行比较:
这里有一张更简单的图片。故意简化了!
集合 是指存储数据的任何东西,称为“元素”(相同类型)。没有更具体的假设。
列表 是一个带有索引的数据集合,其中每个元素都有一个索引。类似于数组,但更灵活。
列表中的数据保留插入顺序。
典型操作:获取第n个元素。
集合 是一个元素的包,每个元素只出现一次(使用它们的equals()
方法区分元素)。
集合中的数据主要存储以了解存在哪些数据。
典型操作:查看列表中是否存在元素。
映射表 类似于列表,但是您可以通过它们的键而不是整数索引访问它们,该键是任何对象。就像PHP中的数组:)
Map中的数据可通过其键进行搜索。
典型操作:通过其ID获取元素(其中ID是任何类型,而不仅仅是int
,如列表的情况)。
Set vs. Map: 在 Set 中,您通过元素本身进行搜索,而在 Map 中,您通过它们的键进行搜索。
N.B. 标准库中的 Sets 确实是按照这种方式实现的:一个 Map,其中键是 Set 元素本身,并带有一个虚拟值。
List vs. Map: 在 List 中,您通过其 int
索引(在 List 中的位置)访问元素,而在 Map 中,您通过其任意类型的键(通常为 ID)访问元素。
List vs. Set: 在 List 中,元素受其位置限制并且可以重复,而在 Set 中,元素仅存在(或不存在)且唯一(在 equals()
的含义下,或对于 SortedSet
的 compareTo()
)