我应该使用哪个 Java 集合?

Posted

技术标签:

【中文标题】我应该使用哪个 Java 集合?【英文标题】:Which Java Collection should I use? 【发布时间】:2014-03-25 07:47:29 【问题描述】:

在这个问题中,How can I efficiently select a Standard Library container in C++11? 是一个方便的流程图,可以在选择 C++ 集合时使用。

我认为这对于不确定应该使用哪个集合的人来说是一个有用的资源,因此我尝试为 Java 找到类似的流程图但无法做到。

有哪些资源和“备忘单”可以帮助人们在使用 Java 编程时选择正确的 Collection?人们如何知道他们应该使用哪些 List、Set 和 Map 实现?

【问题讨论】:

Java Generics and Collections (Naftalin & Wadler) 这本书有一章关于这个。 【参考方案1】:

由于找不到类似的流程图,我决定自己制作一个。

此流程图并未尝试涵盖同步访问、线程安全等或遗留集合,但它确实涵盖了 3 个标准 Set、3 个标准 Maps 和 2 个标准 列表s。

此图片是为此答案创建的,并在Creative Commons Attribution 4.0 International License. 下获得许可。最简单的归属是通过链接到此问题或此答案。

其他资源

可能最有用的其他参考是 oracle 文档中的以下页面,该页面描述了每个 Collection。

HashSet 与 TreeSet

这里详细讨论了何时使用HashSetTreeSet: Hashset vs Treeset

ArrayList vs LinkedList

详细讨论:When to use LinkedList over ArrayList?

【讨论】:

不错!但我必须不同意您的LinkedListArrayList 的决定。首先,如果列表很大,LinkedList 更可取。 LinkedList 具有每个元素的开销,因此它在内存消耗方面比ArrayList 更差。此外,如果大部分访问位于列表末尾,则ArrayList 更可取,因为它提供恒定时间随机元素访问。访问LinkedListnth 元素是O(n) 操作。 ...事实上,使用链表的决定应该总是是“否”。 @MattBall 我在很大程度上同意你的看法。然而 Java LinkedList 是一个双链表,所以在开始和结束时访问都很快。您会注意到,在我推荐使用LinkedList 之前,以上所有三个问题的分支都必须回答是 - 所以换句话说,我同意您的观点,在大多数情况下答案是否定的。诸如队列和出队之类的东西,您不断地从列表区域的末尾添加和删除东西,这是LinkedList 的好用例。 @MattBall 内存使用情况要棘手得多,因为LinkedList 每个元素使用更多内存...ArrayList 永远不会释放内存。这意味着如果您有一个有时会增长到很大但通常很小的列表,那么ArrayList 将提供更差的内存性能。与它所包含的元素相比,List 本身的内存开销通常(尽管并非总是)很小。 Map<K,V> 不是java.util.collection 的一部分 @MehrajMalik 嗯,我同意标签模棱两可。我的意思是 java.util 中的集合。即 java.util.*在此处插入集合名称*【参考方案2】:

主要的非并发、非同步集合总结

Collection:一个接口,表示一个无序的“包”项目,称为“元素”。 “下一个”元素未定义(随机)。

Set:代表Collection 的接口,没有重复项。 HashSet:由Hashtable 支持的Set。当订购不重要时,最快和最小的内存使用量。 LinkedHashSet:一个HashSet,添加了一个链表以插入顺序关联元素。 “下一个”元素是下一个最近插入的元素。 TreeSet:一个Set,其中元素按Comparator 排序(通常是natural ordering)。最慢和最大的内存使用量,但对于基于比较器的排序是必需的。 EnumSet:为单个枚举类型定制的极其快速高效的SetList:表示Collection 的接口,其元素是有序的,每个都有一个数字索引表示其位置,其中零是第一个元素,(length - 1) 是最后一个元素。 ArrayList:由数组支持的List,其中数组的长度(称为“容量”)至少与元素数(列表的“大小”)一样大。当大小超过容量时(当添加(capacity + 1)-th 元素时),将使用(new length * 1.5) 的新容量重新创建数组——这种重新创建速度很快,因为它使用了System.arrayCopy()。删除和插入/添加元素需要将所有相邻元素(向右)移入或移出该空间。访问任何元素都很快,因为它只需要计算 (element-zero-address + desired-index * element-size) 即可找到它的位置。 In most situations,ArrayList 优于 LinkedListLinkedList:由一组对象支持的List,每个对象都链接到它的“前一个”和“下一个”邻居。 LinkedList 也是 QueueDeque。从第一个或最后一个元素开始访问元素,并遍历直到达到所需的索引。插入和删除,一旦通过遍历到达所需的索引,只需重新映射直接相邻的链接以指向新元素或绕过现在删除的元素。 Map:表示Collection 的接口,其中每个元素都有一个标识“键”——每个元素都是一个键值对。 HashMapMap,其中的键是无序的,并由 Hashtable 支持。 LinkedhashMap:键按插入顺序排序。 TreeMapMap,其中键按 Comparator 排序(通常是自然排序)。 Queue:表示Collection 的接口,其中元素通常添加到一端,从另一端移除(FIFO:先进先出)。 Stack:表示Collection 的接口,其中元素通常从同一端添加(推送)和移除(弹出)(LIFO:后进先出)。 Deque:“双端队列”的缩写,通常发音为“deck”。一个链表,通常只在两端(而不是中间)添加和读取。

基本集合图:

将元素的插入与ArrayListLinkedList 进行比较:

【讨论】:

最好的简短总结,一个人可以去任何地方:)【参考方案3】:

更简单的图片在这里。有意简化!

    Collection 是任何保存数据的东西,称为“元素”(相同类型)。没有更具体的假设。

    List 是一个索引数据集合,其中每个元素都有一个索引。类似于数组的东西,但更灵活。

    列表中的数据保持插入顺序。

    典型操作:获取第n个元素。

    Set 是一个元素包,每个元素只有一次(使用equals() 方法区分元素。

    存储集合中的数据主要是为了了解什么数据。

    典型操作:判断一个元素是否存在于列表中。

    Map 类似于 List,但不是通过它们的整数索引访问元素,而是通过它们的 key 访问它们,它是任何对象。就像 php 中的数组一样 :)

    Map 中的数据可以通过它们的键进行搜索。

    典型操作:通过 ID 获取元素(其中 ID 可以是任意类型,而不仅仅是 int 和 List 一样)。

区别

Set vs. Map:在Set中搜索数据他们自己,而在Map中通过他们的键

注意标准库 Set 确实是这样实现的:一个键是 Set 元素本身的映射,并且具有一个虚拟值。

List vs. Map:在 List 中,您可以通过它们的 int 索引(在 List 中的位置)访问元素,而在 Map 中,通过它们的任何类型的键(通常:ID)访问元素

List 与 Set:在 List 中,元素受其位置约束并且可以重复,而在 Set 中,元素只是“存在”(或不存在)并且是唯一的(在 equals() 的含义中,或compareTo()SortedSet)

【讨论】:

【参考方案4】:

这很简单:如果您需要使用映射到它们的键存储值,请使用 Map 接口,否则使用 List 存储可能重复的值,如果您不希望集合中出现重复值,则最后使用 Set 接口.

这里是完整的解释http://javatutorial.net/choose-the-right-java-collection,包括流程图等

【讨论】:

【参考方案5】:

地图

如果选择Map,我制作了这张表格,总结了与 Java 11 捆绑的十个实现中的每一个的特性。

【讨论】:

【参考方案6】:

常用集合,常用集合

【讨论】:

HashMap 不是接口。

以上是关于我应该使用哪个 Java 集合?的主要内容,如果未能解决你的问题,请参考以下文章

我应该使用哪个 Java 库通过 Facebook、Gmail、本地身份验证等进行身份验证?

Java 的 Scanner vs String.split() vs StringTokenizer;我应该使用哪个?

我应该选择哪个 DBMS 来使用 Java 重新排序查询执行计划?

一个合格的Java开发工程师应该具备哪些技能?

我应该使用哪个 jsf-impl?

BackboneJs - 模型或集合是不是应该了解视图