在Java中,以传统的方式迭代数组是否更快?
for (int i = 0; i < a.length; i++)
f(a[i]);
或者使用更简洁的形式:
for (Foo foo : a)
f(foo);
对于ArrayList,答案是否相同?
当然,在大部分应用代码中,答案是没有明显差别的,因此应该使用更简洁的形式以增强可读性。然而,我关注的上下文是重度技术计算,需要执行数十亿次操作,因此即使微小的速度差异也可能具有重要意义。
在Java中,以传统的方式迭代数组是否更快?
for (int i = 0; i < a.length; i++)
f(a[i]);
或者使用更简洁的形式:
for (Foo foo : a)
f(foo);
对于ArrayList,答案是否相同?
当然,在大部分应用代码中,答案是没有明显差别的,因此应该使用更简洁的形式以增强可读性。然而,我关注的上下文是重度技术计算,需要执行数十亿次操作,因此即使微小的速度差异也可能具有重要意义。
public static void main(String[] args)
{
for (String x : args)
{
System.out.println(x);
}
}
使用 javap -c Test
反编译后,我们得到以下内容(针对 main
方法):
public static void main(java.lang.String[]);
Code:
0: aload_0
1: astore_1
2: aload_1
3: arraylength
4: istore_2
5: iconst_0
6: istore_3
7: iload_3
8: iload_2
9: if_icmpge 31
12: aload_1
13: iload_3
14: aaload
15: astore 4
17: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
20: aload 4
22: invokevirtual #3; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
25: iinc 3, 1
28: goto 7
31: return
现在将其更改为使用显式的数组访问:
public static void main(String[] args)
{
for (int i = 0; i < args.length; i++)
{
System.out.println(args[i]);
}
}
这个反编译的结果是:
public static void main(java.lang.String[]);
Code:
0: iconst_0
1: istore_1
2: iload_1
3: aload_0
4: arraylength
5: if_icmpge 23
8: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
11: aload_0
12: iload_1
13: aaload
14: invokevirtual #3; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
17: iinc 1, 1
20: goto 2
23: return
增强型for循环中有一些额外的设置代码,但它们基本上在做相同的事情。 没有涉及到迭代器。 此外,我希望它们能够被JIT编译成更相似的代码。
建议:如果你真的认为这可能会产生显着的差异(只有当循环体绝对微不足道时),那么你应该用你的实际应用程序进行基准测试。 这是唯一重要的情况。
这完全属于 微观优化 的范畴。但其实并不重要。从风格上来讲,我倾向于第二种方式,因为它更加简明扼要,除非你需要循环计数器来做其他的事情。而这些远比这种微观优化更为重要:可读性。
话虽如此,对于ArrayList来说,两种方式的差别不大,但是对于LinkedList来说,第二种方式会更加高效。
测量它。所有性能问题的答案都可能取决于虚拟机版本、处理器、内存速度、缓存等因素。因此,您必须针对您特定的平台进行测量。
个人而言,我更喜欢第二种变体,因为意图更加清晰。如果性能成为问题,我随时可以优化它 - 如果该代码确实对整个应用程序的性能很重要。
对于链表(LinkedList):
for(ClassOfElement element : listOfElements) {
System.out.println(element.getValue());
}
此前已经有回答:
List<Object> list = new ArrayList<Object>();
for (int i=0, d=list.size(); i<d; i++) {
something(list.get(i));
}
但是一般情况下我不会担心这个问题。像这样的优化对你的代码影响不会超过0.1%。尝试使用-prof参数来调用Java,以查看你的代码实际花费时间的地方。
如果您有足够大的数据集,更快的方法是使用分叉-合并框架的ParallelArray。
f()
非常短,否则您不太可能注意到差异。 - user207421