首页 / 知识

选择Java Collection实现的经验法则?

2023-04-14 11:40:00

Rule of thumb for choosing an implementation of a Java Collection?

任何人都有很好的经验法则可以在Java Collection接口的不同实现(例如List,Map或Set)之间进行选择?

例如,通常,为什么或在什么情况下,我更喜欢使用Vector或ArrayList,Hashtable或HashMap?


我真的很喜欢Sergiy Kovalchuk博客文章中的备忘单:

Java Map/Collection Cheat Sheet

Alexander Zagniotov的流程图更为详细,但不幸的是它是离线的。但是,Wayback Machine有一个博客副本:

Alexander Zaniotovs flowchart for choosing Collection implementations


我假设您从上述答案中知道List,Set和Map之间的区别。为什么要在他们的实现类之间进行选择是另一回事。例如:

列表:

  • ArrayList的检索速度很快,但插入速度却很慢。这对于读取很多但不会插入/删除很多的实现很有用。它把数据保存在一个连续的内存块中,因此每次需要扩展时,它都会复制整个阵列。
  • LinkedList的检索速度较慢,但??插入速度较快。这对于插入/删除很多但读得很少的实现很有用。它不会将整个阵列保持在一个连续的内存块中。
  • 组:

  • HashSet不能保证迭代的顺序,因此是最快的。它具有较高的开销,并且比ArrayList慢,因此,当其哈希速度成为重要因素时,除了大??量数据外,您不应该使用它。
  • TreeSet使数据保持有序,因此比HashSet慢。
  • 映射:HashMap和TreeMap的性能和行为与Set实现平行。

    不应该使用Vector和Hashtable。它们是新的Collection层次结构发布之前的同步实现,因此速度很慢。如果需要同步,请使用Collections.synchronizedCollection()。


    我总是根据用例逐案做出决定,例如:

    • 我需要保留订单吗?
    • 我将拥有空键/值吗? DUPS?
    • 是否可以被多个线程访问
    • 我需要一个键/值对吗
    • 我需要随机访问吗?

    然后,我简要介绍了我的第5版Java,比较了大约20种左右的选项。第五章中有一些漂亮的表格,可以帮助您找出合适的表格。

    好吧,也许如果我袖手旁观,简单的ArrayList或HashSet可以解决问题,我将不会全看。 ;),但是如果我的预期用途有任何复杂之处,那么您肯定我在书中。顺便说一句,尽管我认为Vector应该是"旧帽子"-我已经好几年没有使用过了。


    从理论上讲,存在一些有用的Big-Oh折衷方案,但实际上,这些折衷方案几乎没有关系。

    在实际的基准测试中,即使使用大型列表和诸如"在前面有很多插入"之类的操作,ArrayList也要优于LinkedList。学者们忽略了这样一个事实,即真实的算法具有恒定的因素,可以使渐近曲线不堪重负。例如,链表需要为每个节点分配额外的对象,这意味着创建节点的速度较慢,而内存访问特性则更差。

    我的规则是:

  • 始终以ArrayList和HashSet和HashMap开头(即不是LinkedList或TreeMap)。
  • 类型声明应始终是接口(即List,Set,Map),因此,如果探查器或代码审查证明是这样,则可以在不破坏任何内容的情况下更改实现。

  • 关于第一个问题...

    列表,地图和集合具有不同的用途。我建议在http://java.sun.com/docs/books/tutorial/collections/interfaces/index.html上阅读有关Java Collections Framework的内容。

    更具体一点:

    • 如果需要类似数组的数据结构并且需要遍历元素,请使用List
    • 如果您需要像字典一样的东西,可以使用地图
    • 如果只需要确定某项是否属于该集合,则使用集合。

    关于第二个问题...

    Vector和ArrayList之间的主要区别是前者是同步的,后者是不同步的。您可以在实践中阅读有关Java并发性的更多信息。

    Hashtable(注意T不是大写字母)和HashMap之间的区别是相似的,前者是同步的,后者是不同步的。

    我想说,偏爱一个或另一个实现并没有经验法则,这实际上取决于您的需求。


    对于未排序的最佳选择,十分之九以上是:ArrayList,HashMap,HashSet。

    Vector和Hashtable是同步的,因此可能会慢一些。很少有人想要同步的实现,而且当您执行同步操作时,它们的接口还不够丰富,因此无法使用同步。对于Map,ConcurrentMap添加了额外的操作以使该接口有用。 ConcurrentHashMap是ConcurrentMap的良好实现。

    LinkedList几乎从来不是一个好主意。即使您进行了大量插入和删除操作,但是如果您使用索引来指示位置,那么也需要遍历列表以找到正确的节点。 ArrayList几乎总是更快。

    对于"地图"和"集合",哈希变体的速度将比树/排序的速度快。哈希算法倾向于具有O(1)性能,而树将是O(log n)。


    正如其他答案中所建议的那样,根据用例,有不同的方案可以使用正确的收集。我列出几点

    数组列表:

    • 大多数情况下,您只需要存储或遍历"一堆东西",然后再遍历它们。迭代更快,因为它基于索引。
    • 每当您创建ArrayList时,就会为其分配固定数量的内存,一旦超出,它将复制整个数组

    链表:

    • 它使用双向链表,因此插入和删除操作将很快,因为它只会添加或删除节点。
    • 检索很慢,因为它必须遍历节点。

    HashSet的:

    • 对项目做出其他是非决定,例如"该商品是英文单词吗?","该商品在数据库中吗?" ,"该项目属于此类别吗?"等等

    • 记住"您已经处理过哪些项目",例如进行网络爬网时;

    HashMap的:

    • 在需要说"对于给定的X,Y是什么"的情况下使用?它通常对于实现内存中的缓存或索引(即键值对)非常有用,例如:
      对于给定的用户ID,其缓存名称/用户对象是什么?
    • 始终与HashMap一起执行查找。

    Vector和Hashtable已同步,因此速度较慢;如果需要同步,请使用Collections.synchronizedCollection()。
    选中此以查看排序的集合。
    希望这一切。


    列表允许重复项,而集合仅允许一个实例。

    每当需要执行查找时,我都会使用Map。

    对于特定的实现,"地图"和"集合"有保留顺序的变体,但很大程度上取决于速度。我倾向于将ArrayList用于较小的列表,将HashSet用于较小的集合,但是有许多实现(包括您自己编写的任何实现)。 HashMap在地图中非常常见。除了"合理地小"以外,您还必须开始担心内存,以便在算法上更加具体。

    如果您对硬数字感兴趣,则此页面上有许多动画图像以及用于测试LinkedList与ArrayList的示例代码。

    编辑:我希望以下链接能够演示这些东西实际上只是工具箱中的项目,您只需要考虑一下您的需求是什么:请参阅Maps,List和Set的Commons-Collections版本。


    好吧,这取决于您的需求。 一般准则是:

    List是一个集合,其中数据按插入顺序保留,并且每个元素都获得索引。

    Set是一袋没有重复的元素(如果重新插入相同的元素,则不会添加)。 数据没有顺序的概念。

    映射您可以通过键访问和写入数据元素,这些键可以是任何可能的对象。

    enter image description here
    出处:https://stackoverflow.com/a/21974362/2811258

    有关Java集合的更多信息,请查看本文。


    我发现Bruce Eckel的《 Java思维》非常有用。他很好地比较了不同的收藏。我曾经保存过一张他发表的图表,该图表显示了我的立方体墙上的继承继承作为快速参考。我建议您做的一件事是记住线程安全性。性能通常意味着线程不安全。


    经验法则选择接口都有

    最新内容

    相关内容

    猜你喜欢