為什麼 Collections.addAll 應該比 c.addAll 更快

2022-09-01 04:34:49

Java API文档说了以下关于Collections.addAll

此方便方法的行为与 c.addAll(Arrays.asList(elements))的行为相同,但此方法在大多数实现下可能运行得更快。

因此,如果我理解正确,a)比b慢):

a)

Collection<Integer> col = new ArrayList<Integer>();
col.addAll(Arrays.asList(1, 2, 3, 4, 5));

b)

Collection<Integer> col = new ArrayList<Integer>();
// Collections.addAll(col, Arrays.asList(1, 2, 3, 4, 5)); <-- won't compile
Collections.addAll(col, 1, 2, 3, 4, 5);

任何人都可以向我解释一下,为什么会这样?

已编辑:更正了代码示例。thx 至 多基因添加剂


答案 1

让我们仔细看看其中两个:

// a)
col.addAll(Arrays.asList(1, 2, 3, 4, 5));

以下是发生的情况:

  1. varags + autoboxing createsInteger[]
  2. Arrays.asList创建由数组支持的List<Integer>
  3. addAll迭代使用Collection<Integer>Iterator<Integer>
// b)
Collections.addAll(col, 1, 2, 3, 4, 5);

以下是发生的情况:

  1. varargs + autoboxing createsInteger[]
  2. addAll循环访问数组(而不是Iterable<Integer>)

我们现在可以看到这可能更快,因为:b)

  • Arrays.asList跳过调用,即不创建中介。List
  • 由于元素是在数组中给出的(这要归功于 varargs 机制),因此迭代它们可能比使用 Iterator 更快。

也就是说,除非分析显示其他情况,否则差异不太可能是“显着的”。不要过早优化。虽然 Java 集合框架类可能比数组慢,但它们对于大多数应用程序的性能都足够好。

接口链接

另请参见

相关问题


总结

  • 如果要从数组中添加元素,可以使用Collections.addAll(col, arr)
    • 请记住,varargs也是使用数组完成的
  • 如果要从 中添加元素,请使用Collectioncol.addAll(otherCol)
    • 不要例如Collections.addAll(col, otherCol.toArray())
      • 这种迂回的方式可能会慢一些!
  • 这并不是说一个比另一个快得多
    • 这是关于跳过不必要的步骤,鉴于目前的情况

答案 2

它可能更快的唯一原因是它避免了对Arrays.asList的调用,这应该相对便宜,因为它只是包装数组。某些集合实现(例如 LinkedList)在添加元素之前将传递的集合转换回数组,从而导致额外的开销。

另一方面,ArrayList.addAll 在添加任何元素之前分配一次所需的空间,因此当 Collections.addAll 需要多次调整支持数组的大小时,应该会快得多。

总而言之,当重复向集合中添加几个元素时,Collections.addAll可能会更快,但我怀疑这种情况是否会成为性能瓶颈。


推荐