【问题标题】:How do I select the right List implementation?如何选择正确的 List 实现?
【发布时间】:2016-05-24 08:58:50
【问题描述】:

来自this CodeReview answer

您似乎将 ArrayList 用于所有目的。 Java 中还有其他列表类型比 ArrayList 更适合某些情况。你应该看看那些并试着感受一下什么时候使用哪个列表。在这种特殊情况下,即LinkedList 更好。

我也倾向于大量使用ArrayList,并且看不到选择其他列表类型背后的逻辑。

List docs 显示五个主要的 List 子类:ArrayListCopyOnWriteArrayListLinkedListStackVector

来自ArrayList 文档,

size、isEmpty、get、set、iterator 和 listIterator 操作在恒定时间内运行。添加操作在摊销常数时间内运行,即添加 n 个元素需要 O(n) 时间。所有其他操作都以线性时间运行(粗略地说)。与 LinkedList 实现相比,常数因子较低。

这表明 ArrayList 的性能通常会优于 LinkedListthis heavily upvoted question 支持的断言),尽管 LinkedList 文档对性能没有很好的了解:

所有操作都按照双向链表的预期执行。

CopyOnWriteArrayList 似乎只对不变的列表有用,因为每次修改的完整快照对于正常使用来说似乎非常昂贵。

即使是 Stack 文档也不推荐使用它:

Deque 接口及其实现提供了一组更完整和一致的 LIFO 堆栈操作,应优先使用该类。

由于Vector 是同步的,而List 的其余子类不是同步的,所以在我看来Vector 将是线程安全环境中的最佳选择。

然而,即使在阅读了文档之后,我仍然认为我不明白 TwoThe 的答案来自哪里。 CopyOnWriteArrayListVector 似乎都有一个专门的用例,Stack 似乎不值得使用,ArrayList 似乎优于 LinkedList

我在这里遗漏了什么,在什么情况下另一个 List 实现会优于 ArrayList

【问题讨论】:

  • 仅供参考:Vector 通常被认为已弃用,如果您需要同步功能,可以使用Collections.synchronizedList
  • 并不总是可以知道哪一个总是正确的(对于方法/API)。在某些情况下,您需要ArrayList 擅长的随机访问,有时您需要LinkedList 擅长的串行/线性访问。通常,如果我的方法在内部使用ArrayList。我会让方法返回List,如果我想使用LinkedList,我可能会考虑返回Iterator,这会强制使用进入串行访问模式,但你并不总是知道其他人可能想要什么来自您的数据
  • 对于事件触发,CopyOnWrite 几乎可以肯定是正确的实现。并发是一个大问题。读取比写入更频繁。

标签: java performance list


【解决方案1】:

我同意ArrayList 是许多用途的正确选择。 LinkedList 每个元素使用 8 或 16 字节的内存作为指针,并且如您所说,索引是 O(length)。

那么LinkedLists 有什么优势呢?

  • 在迭代期间使用remove() 删除是恒定时间。 ArrayList 是 O(length)。
  • 添加新的列表节点总是需要相同的时间。当ArrayLists 空间不足时,会在后台分配更大的内存块,并复制所有内容。虽然每个元素的许多操作的摊销时间是恒定的,但单个 add() 的成本是 O(length)。如果不能接受这种周期性延迟,则不能使用ArrayList

至于其他人,Vector 可以追溯到 Java 的早期。它是线程安全的。因为这增加了每个操作的成本,所以它的使用或多或少被弃用,有利于ArrayList。当您需要线程安全时,您可以使用SynchronizedList 包装器围绕ArrayList。类似地,Stack 或多或少被弃用,取而代之的是更现代而不是线程安全的Deque

CopyOnWriteArrayList 是一个线程安全的数据列表,它通过在任何元素发生变化时制作完整数组的副本这一有点不寻常的措施来获得其安全性。虽然这听起来很疯狂,但如果有许多线程在同一个数组上迭代是有道理的,因为更改不必等待迭代全部完成,而其他并发列表通常是这种情况。

【讨论】:

    【解决方案2】:

    简单地说,在这种特殊情况下,您是正确的,而 TwoThe 是不正确的。正如您所指出的,由于您在这里所做的只是adding 和循环,因此LinkedList 只会减慢您的速度。这是ArrayList 的一个完全有效的用例,当您不确定要使用哪个List 时,默认为ArrayList 并没有错。

    有关您何时应该使用LinkedList 的更详细说明,this question 的答案可能会有所帮助。

    【讨论】:

      猜你喜欢
      • 2021-05-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-13
      • 1970-01-01
      • 1970-01-01
      • 2021-01-17
      • 2020-03-31
      相关资源
      最近更新 更多