[英]Is it better to set size of a Java Collection in constructor?
如果我知道当时的大小,最好将Collection
的大小传递给Collection
构造函数吗? 在扩展Collection
和分配/重新分配方面的节省效果是否显着?
如果我知道Collection
最小大小但不知道上限,该怎么办。 至少以最小的尺寸创建它仍然值得吗?
不同的集合对此有不同的性能影响,对于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
如果将max设置为10000000的值的10倍,则得出:
Preall: 510
Resizing: 935
因此,即使大小不同,您也可以看到比率保持不变。
这几乎是最坏的测试,但是一次填充一个元素一个数组很常见,您会发现速度大约相差2倍。
所有集合都是自动扩展的。 不知道边界不会影响其功能(直到遇到其他问题,例如使用所有可用内存等),但是可能会影响其性能。
有一些收藏。 最值得注意的是ArrayList,因为要复制整个基础数组,所以自动扩展的成本很高。 数组列表的默认大小为10,每次达到最大值时,其大小都会增加一倍。 因此,假设您知道您的arraylist将包含110个对象,但不指定其大小,则将发生以下复制
复制10-> 20
复制20-> 40
复制40-> 80
复制80-> 160
通过预先告诉arraylist它包含110个项目,您可以跳过这些副本。
即使您错了也没关系。 集合仍将自动展开,并且您仍将避免某些副本。 降低性能的唯一方法是,如果您的猜测太大了:这将导致分配给集合的内存过多
好,这是我的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
如果增加初始大小,则可以使您的心脏感到温暖,但客观地说,客户不太可能注意到差异。
在少数情况下,大小是众所周知的(例如,当将已知数量的元素填充到新集合中时),出于性能原因可以进行设置。
通常,最好省略它,而改用默认构造函数,这样可以使代码更简单和更好理解。
对于基于数组的集合,重新调整大小是一项非常昂贵的操作。 这就是为什么为ArrayList
传递准确大小是一个好主意的原因。
如果将大小设置为最小大小( MIN
),然后将MIN
+1个元素添加到集合中,则需要重新调整大小。 ArrayList()
调用ArrayList(10)
因此如果MIN
足够大,那么您将获得一些好处。 但是最好的方法是使用期望的集合大小创建ArrayList
。
但是可能您更喜欢LinkedList,因为它没有添加元素的任何开销(尽管list.get(i)
开销为O(i))
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.