【发布时间】:2013-11-07 05:15:37
【问题描述】:
考虑以下 Java 代码(完整、编译和运行良好)。
代码创建一个包含 5,000,000 个整数(1 到 500 万)的数组,对其进行循环,并创建一个它找到的完美正方形的 ArrayList。使用简单的技术检测完美的正方形,而不是位操作,但这不是当前问题的重点。
在数学上,在 1 到 5M 之间,有 2236 个完美正方形。因此,放入完美正方形的 ArrayList 的最终大小为 2236。
import java.util.ArrayList;
public class PerfSquares {
public static ArrayList<Integer> perfectSquares(int[] arr) {
ArrayList<Integer> al = new ArrayList<Integer>();
// ArrayList<Integer> al = new ArrayList<Integer>(arr.length);
for (int i = 0; i < arr.length; i++) {
double root = Math.sqrt(arr[i]);
int irt = (int) Math.floor(root);
if (irt * irt == arr[i]) {
al.add(arr[i]);
}
}
return al;
}
public static void main(String[] args) {
int[] arr = new int[5000000];
for (int i = 0; i < arr.length; i++) {
arr[i] = i + 1;
}
long s = System.currentTimeMillis();
perfectSquares(arr);
long e = System.currentTimeMillis();
System.out.println(e - s);
}
}
我想重点介绍 ArrayList 的声明。这两行,其中一行被注释掉:
ArrayList<Integer> al = new ArrayList<Integer>();
//ArrayList<Integer> al = new ArrayList<Integer>(arr.length);
当我使用第一个声明(没有明确提供的大小)运行时,我看到的 timediff 是:
~96 milliseconds.
当我使用第二个声明(使用明确提供的大小)运行时,timediff 增加到:
~105 milliseconds
问题:
为什么会这样?第二种情况(提供尺寸)不应该更快吗?
根据我的理解,在第一种情况下,当我们在创建 ArrayList 时省略 size 参数时,会在后台初始化一个长度为 10 的数组。而当超过这个容量时,会分配一个容量更大(不知道大多少)的新数组,并将之前的元素复制过来。
对于 2236 个元素且未指定初始大小,此“超出上限 - 分配新 - 复制 - 追加更多直到上限”循环应重复多次,从而减慢速度。
因此,我预计提供的大小声明会更快 - 因为分配将发生一次,并且不会发生容量超出/新数组创建和复制发生。
或者这基本上是因为 2236 附加到 ArrayList,即使有所有 cap-exceeds-copy-over 循环,仍然比创建大小为 5,000,000 的 ArrayList 更快?
【问题讨论】:
-
只运行一次,System.currentTimeMillis() 的精度如此差,并获得如此小的差异,导致毫无意义的结果。执行 1000 次,然后使用 System.nanoTime() 开始测量接下来的 1000 次执行,然后平均结果。
-
不要创建具有完整数组大小的
ArrayList,而是尝试使用(int) Math.sqrt(arr.size()),这大约是完美正方形的数量。如果您想确定,请添加一些。 -
@SidCool 坏主意。当我们谈论性能时,LinkedList从来没有一个选项。
-
@Aaron:使用
LinkedList,即使追加和迭代也会慢得多(2 倍加上 GC 开销)。你只有一个好的操作:在Iterator的位置移除。这几乎没有。虽然LinkedList有很好的用例,但它们比大多数人预期的要少得多。 -
@Aaron 我什至认为将 LinkedList 添加到标准 Java API 是一个错误。 LinkedList 仅适用于非常罕见和特定的情况。在我 6 年的 Java 经验中我从未使用过它。与 TreeMap/Set、Deque 等数据结构不同。 On Github LinkedList 的使用频率高于 TreeMap、TreeSet、Deque 和 ArrayDeque放在一起。这令人失望。
标签: java arrays performance arraylist