如果我知道那时的大小,是否最好将Collection
的大小传递给Collection
构造函数?扩展Collection
和分配/重新分配显着的节约效果是什么?
如果我知道Collection
的最小尺寸而不是上限,该怎么办?至少在最小尺寸下仍然值得创造吗?
答案 0 :(得分:5)
不同的集合对此有不同的性能影响,对于ArrayList,保存可以非常明显。
import java.util.*;
public class Main{
public static void main(String[] args){
List<Integer> numbers = new ArrayList<Integer>(5);
int max = 1000000;
// Warmup
for (int i=0;i<max;i++) {
numbers.add(i);
}
long start = System.currentTimeMillis();
numbers = new ArrayList<Integer>(max);
for (int i=0;i<max;i++) {
numbers.add(i);
}
System.out.println("Preall: "+(System.currentTimeMillis()-start));
start = System.currentTimeMillis();
numbers = new ArrayList<Integer>(5);
for (int i=0;i<max;i++) {
numbers.add(i);
}
System.out.println("Resizing: "+(System.currentTimeMillis()-start));
}
}
结果:
Preall: 26
Resizing: 58
以max000设置为10000000处的值的10倍运行会产生:
Preall: 510
Resizing: 935
所以你甚至可以看到不同尺寸的比例保持不变。
这几乎是最糟糕的测试,但是一次填充一个数组元素非常常见,您可以看到速度差异大约为2 *。
答案 1 :(得分:4)
所有馆藏都在自动扩展。不知道边界不会影响它们的功能(直到你遇到其他问题,比如使用所有可用的内存等),但它可能会影响它们的性能。
有一些收藏品。最值得注意的是ArrayList,自动扩展是昂贵的,因为整个底层数组被复制;数组列表的默认大小为10,然后每次达到最大值时加倍。所以,假设你知道你的arraylist将包含110个对象,但是没有给它一个大小,会发生以下副本
复制10 - &gt; 20个
复制20 - &gt; 40个
复制40 - &gt; 80个
复制80 - &gt; 160
通过告诉arraylist它包含110个项目,你跳过这些副本。
即使你错了也没关系。该集合仍将自动扩展,您仍然可以避免一些副本。你可以降低性能的唯一方法是你的猜测是否太大:这将导致分配给集合的内存太多
答案 2 :(得分:4)
好的,这是我的jmh代码:
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@BenchmarkMode(Mode.AverageTime)
@Warmup(iterations = 3, time = 1)
@Measurement(iterations = 3, time = 1)
@Fork(3)
public class Comparison
{
static final int size = 1_000;
@GenerateMicroBenchmark
public List<?> testSpecifiedSize() {
final ArrayList<Integer> l = new ArrayList(size);
for (int i = 0; i < size; i++) l.add(1);
return l;
}
@GenerateMicroBenchmark
public List<?> testDefaultSize() {
final ArrayList<Integer> l = new ArrayList();
for (int i = 0; i < size; i++) l.add(1);
return l;
}
}
我size = 10_000
的结果:
Benchmark Mode Thr Cnt Sec Mean Mean error Units
testDefaultSize avgt 1 9 1 80.770 2.095 usec/op
testSpecifiedSize avgt 1 9 1 50.060 1.078 usec/op
size = 1_000
的结果:
Benchmark Mode Thr Cnt Sec Mean Mean error Units
testDefaultSize avgt 1 9 1 6.208 0.131 usec/op
testSpecifiedSize avgt 1 9 1 4.900 0.078 usec/op
添加初始尺寸,如果这会让您感觉更温暖,但客观地说,您的客户极不可能注意到差异。
答案 3 :(得分:0)
在极少数情况下,当大小众所周知时(例如,在将新数量的元素填入新集合时),可能会出于性能原因进行设置。
通常最好省略它并使用默认构造函数,从而导致更简单,更易理解的代码。
答案 4 :(得分:0)
对于基于数组的集合,重新调整大小是一项非常昂贵的操作。这就是为ArrayList
传递确切大小的原因是个好主意。
如果您将大小设置为最小尺寸(MIN
),然后添加到集合MIN
+ 1元素,那么您将重新调整大小。 ArrayList()
调用ArrayList(10)
,因此如果MIN
足够大,那么您将获得一些优势。但最好的方法是使用期待集合大小创建ArrayList
。
但是你可能更喜欢LinkedList,因为添加元素没有任何成本(虽然list.get(i)
有O(i)成本)