【问题标题】:Which implementation of List to use?使用哪个 List 实现?
【发布时间】:2011-04-19 08:15:47
【问题描述】:

在我的程序中,我经常使用集合来存储对象列表。目前我使用 ArrayList 来存储对象。 我的问题是:这是最佳选择吗?使用 LinkedList 会更好吗?还是别的什么?

要考虑的标准是:

  • 内存使用情况
  • 性能

我需要的操作是:

  • 将元素添加到集合中
  • 遍历元素

有什么想法吗?

更新:我的选择是:ArrayList :) 基于此讨论以及以下讨论:

【问题讨论】:

标签: java performance memory-management collections


【解决方案1】:

我总是默认使用 ArrayList,在你的情况下也是如此,除非

  • 我需要线程安全(在这种情况下,我开始查看 java.util.concurrent 中的 List 实现)
  • 我知道我将对 List 进行大量插入和操作,否则分析表明我对 ArrayList 的使用是一个问题(非常罕见)

至于在第二种情况下选择什么,这个 SO.com 线程有一些有用的见解:List implementations: does LinkedList really perform so poorly vs. ArrayList and TreeList?

【讨论】:

  • 感谢您提供非常有趣的讨论的链接!
  • @Thilo - 我从来没有说过。我说除非我需要线程安全,否则我默认使用 ArrayList。为了清楚起见,我将修改我的答案,说我去 java.util.concurrent 中的 List 实现。
【解决方案2】:

链表在添加/删除内部元素(即不是头部或尾部)方面更快

Arraylist 的迭代速度更快

【讨论】:

  • 嗯。迭代时可能会更快,尽管我不认为这会超出边际。真正的好处应该是以随机顺序访问元素......
  • 据我所知,两者都有 O(n) 迭代。
  • O(n) 迭代 N 个元素。如果您在此处阅读并在此处更改方式,则链表迭代器将不会抛出...
【解决方案3】:

这是插入优化与检索优化之间的经典权衡。您描述的任务的常见选择是 ArrayList。

【讨论】:

  • 迭代整个集合的速度很快,而且由于链表中的链接必须存储在某个地方,因此内存占用更少。
【解决方案4】:

ArrayList 适合您(和大多数其他)目的。它具有非常小的内存开销,并且对于大多数操作具有良好的摊销性能。不理想的情况比较少见:

  • 列表很大
  • 您经常需要执行以下操作之一:
    • 在迭代期间添加/删除项目
    • 从列表的开头删除项目

【讨论】:

  • 详细说明这一点:ArrayList的迭代器如果在迭代过程中检测到变化会抛出异常。此外,出于显而易见的原因,从头开始删除 a-la 队列最好通过链表完成。
  • @GregC:当有并发修改时,LinkedList 的迭代器不会抛出异常?如果是这样,那为什么好?
  • 看来我错了......将不得不尝试......引用:“此类的迭代器和 listIterator 方法返回的迭代器是快速失败的:如果列表在结构上被修改在迭代器创建后的任何时候,除了通过迭代器自己的 remove 或 add 方法外,迭代器都会抛出 ConcurrentModificationException。因此,面对并发修改,迭代器快速而干净地失败,而不是冒险任意,未来不确定时间的非确定性行为。”
  • 我的想法是......如果有人正在修改列表,并且他们没有改变被迭代元素的左侧或右侧的任何内容,那么就没有问题。
  • @GregC:乍一看这听起来很合乎逻辑,但竞争条件并不是那么简单。不过,您误解了我的意思:Iterator(和 ListIterator)接口本身具有添加/删除方法,可用于在迭代期间安全地修改列表(对于 LinkedList,效率更高)
【解决方案5】:

如果您只是在列表末尾添加,ArrayList 应该没问题。来自ArrayList的文档:

除了添加一个元素具有恒定的摊销时间成本这一事实之外,没有指定增长策略的细节

ArrayList 也应该比链接列表使用更少的内存,因为您不需要为链接使用空间。

【讨论】:

    【解决方案6】:

    这取决于您的使用情况。

    您是否添加到列表的末尾?两者都很好。 您是否添加到列表的开头? LinkedList 对此更好。 你需要随机访问(你会打电话给get(n)吗)? ArrayList 更适合这个。

    两者都擅长迭代,next() 的两个 Iterator 实现都是 O(1)。

    如有疑问,请使用每个实现测试您自己的应用并做出自己的选择。

    【讨论】:

      【解决方案7】:

      我知道我迟到了,但也许 this page 可以帮助你,不仅现在,而且在未来......

      【讨论】:

        【解决方案8】:

        根据您的标准,您应该使用 LinkedList。

        LinkedList 实现了 Deque 接口,这意味着它可以在恒定时间 (1) 中添加到列表的开头或结尾。此外,ArrayList 和 LinkedList 都会在 (N) 时间内迭代。

        您不应该仅仅因为在列表已满时添加元素的成本而使用 ArrayList。在这种情况下,添加元素将是 (N),因为正在创建新数组并将所有元素从一个数组复制到另一个数组。

        此外,ArrayList 会占用更多内存,因为您的后备数组的大小可能未完全填满。

        【讨论】:

        • 我的同事刚刚写了一个简单的测试——将元素添加到不同位置的不同大小的列表中。结果是这样的:我做了我自己朴实无华的测试。结果如下: - 简单添加(List.add(“A”)):ArrayList 比 LinkedList 快 3-5 倍,大小范围为 1 到 100 000。
        • 添加到列表的头部 (List.add(0, “A”): 大小为 1 时,时间相等;大小为 100 的 LinkedList 快~2 倍;大小为 1000 的 LinkedList 快~10次;大小为 10000 的链表快约 50 倍;大小为 50000 的链表快约 80 倍
        • 随机添加 (List.add(Math.random(list.size()), “A”)):ArrayList 比 LinkedList 快 2 倍在相同的范围内(1 到 100 000)跨度>
        • 所以,@rrlichwa,很遗憾,我不能同意你关于生产力的看法:(
        • 关于内存使用,我相信 ArrayList 使用内存更紧凑,因为它不保存任何内部服务的东西(如链接到 LinkedList 中的下一个元素)
        猜你喜欢
        • 2016-12-20
        • 2013-05-26
        • 1970-01-01
        • 1970-01-01
        • 2012-10-14
        • 2010-12-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多