关于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到polygenelubricants
答案 0 :(得分:48)
让我们仔细看看其中两个:
// a) col.addAll(Arrays.asList(1, 2, 3, 4, 5));
以下是发生的事情:
Integer[]
Arrays.asList
创建一个由数组支持的List<Integer>
addAll
使用Collection<Integer>
Iterator<Integer>
进行迭代
醇>
// b) Collections.addAll(col, 1, 2, 3, 4, 5);
以下是发生的事情:
Integer[]
addAll
遍历数组(而不是Iterable<Integer>
)我们现在可以看到b)
可能更快,因为:
Arrays.asList
调用被跳过,即没有创建中间人List
。Iterator
更快。尽管如此,除非剖析显示其他情况,否则差异可能不大“重要”。不要过早优化。虽然Java Collection Framework类可能比数组慢,但它们对大多数应用程序的执行效果都不错。
Collections.addAll(Collection<? super T> c, T... elements)
- varargs,即基于数组的Collection.addAll(Collection<? extends E> c)
- Collection
- 基于Collections.addAll(col, arr)
Collection
中的元素,请使用col.addAll(otherCol)
Collections.addAll(col, otherCol.toArray())
答案 1 :(得分:3)
它可能更快的唯一原因是它避免了对Arrays.asList的调用,它应该相对便宜,因为它只是包装数组。某些Collection实现(例如LinkedList)在添加元素之前将传递的集合转换回数组,从而导致额外的开销。
另一方面,ArrayList.addAll在添加任何元素之前分配所需的空间一次,因此当Collections.addAll需要多次调整后备数组的大小时,它应该快得多。
总之,当集合中只重复添加少量元素时,Collections.addAll会更快,但我怀疑这种情况会不会成为性能瓶颈。
答案 2 :(得分:1)
(让我们在SE平台6上构建)
这完全取决于实际的集合实现。在你的例子中我们有
Collection<Integer> col = new ArrayList<Integer>();
和addAll
中的ArrayList
方法被覆盖。没有任何迭代。
这是来源:
public boolean addAll(Collection<? extends E> c) {
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacity(size + numNew); // Increments modCount
System.arraycopy(a, 0, elementData, size, numNew);
size += numNew;
return numNew != 0;
}
您可能会注意到c.toArray()
也取决于实际实施。同样,在您的情况下,Arrays.asList()
会导致ArrayList
toArray()
方法的版本如下所示:
public Object[] toArray() {
return Arrays.copyOf(elementData, size);
}
此静态方法基于System.arraycopy
所以我们实际处理的是System.arraycopy
的两次调用,实际上并不是那么糟糕,因为它是一种原生方法,专门针对当前操作系统进行了优化。
所以,总结一下polygenelubricants先生的风格:
Integer[]
Arrays.asList
创建ArrayList<Integer>
ArrayList.addAll
调用System.arraycopy(size)
x2,size = 5 在你的情况下,数组Collections.addAll
中的5个对象的cource速度更快。但与这么小的阵列大小无关。另一方面,如果它是数组中的100k元素,则col.addAll(Arrays.asList(...))
效率更高'因为本机方法它是我们处理的单个memcpy / memmove,而不是100k迭代/复制操作。 / p>
而且,这一切都取决于集合的实现。例如,LinkedList
将按预期迭代它。
答案 3 :(得分:1)
以下是@polygenelubricants提到的每个步骤的(近似)关联时间复杂度成本函数:
a)对参数列表进行3次迭代〜= C(3N)
b)参数列表上的2次迭代〜= C(2N)
显然它们都是O(N),但是方法b)在方法a)上节省~N比较。希望这对任何对定量解释感兴趣的人都有帮助。