在Java中,我通常会像下面这样使用for循环:
for (int i = 0; i < max; i++) {
something
}
但最近我的同事这样输入:
for (int i = 0; i < max; ++i) {
something
}
他说后者会更快。这是真的吗?
在Java中,我通常会像下面这样使用for循环:
for (int i = 0; i < max; i++) {
something
}
但最近我的同事这样输入:
for (int i = 0; i < max; ++i) {
something
}
他说后者会更快。这是真的吗?
不,这不是真的。你可以通过计时每个循环的大量迭代来衡量性能,但我相当确定它们将是相同的。
这个谣言来自C语言,其中++i
被认为比i++
更快,因为前者可以通过增加i然后返回它来实现,而后者可能会通过将i的值复制到临时变量中,增加i,然后返回临时变量来实现。第一个版本不需要进行临时拷贝,所以许多人认为它更快。然而,如果该表达式用作语句,则现代C编译器可以优化掉临时拷贝,因此实际上没有区别。
这个问题需要一些Java字节码。请考虑以下代码:
public class PostPre {
public static void main(String args[]) {
int n = 5;
loop1(n);
loop2(n);
}
public static void loop1(int n) {
for (int i = 0; i < n; i++) {}
}
public static void loop2(int n) {
for (int i = 0; i < n; ++i) {}
}
}
现在编译并反汇编它:
$ javac PostPre.java; javap -c PostPre.class
Compiled from "PostPre.java"
public class PostPre {
public PostPre();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: iconst_5
1: istore_1
2: iload_1
3: invokestatic #2 // Method loop1:(I)V
6: iload_1
7: invokestatic #3 // Method loop2:(I)V
10: return
public static void loop1(int);
Code:
0: iconst_0
1: istore_1
2: iload_1
3: iload_0
4: if_icmpge 13
7: iinc 1, 1
10: goto 2
13: return
public static void loop2(int);
Code:
0: iconst_0
1: istore_1
2: iload_1
3: iload_0
4: if_icmpge 13
7: iinc 1, 1
10: goto 2
13: return
}
loop1()
和loop2()
具有相同的字节码。
请在您的环境中尝试此操作。
public class IsOptmized {
public static void main(String[] args) {
long foo; //make sure the value of i is used inside the loop
long now = 0;
long prefix = 0;
long postfix = 0;
for (;;) {
foo = 0;
now = System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
foo += i;
}
postfix = System.currentTimeMillis() - now;
foo = 0;
now = System.currentTimeMillis();
for (int i = 0; i < 1000000000; ++i) {
foo += i;
}
prefix = System.currentTimeMillis() - now;
System.out.println("i++ " + postfix + " ++i " + prefix + " foo " + foo);
}
}
}
i++ 1690 ++i 1610 foo 499999999500000000
i++ 1701 ++i 1610 foo 499999999500000000
i++ 1701 ++i 1600 foo 499999999500000000
i++ 1701 ++i 1610 foo 499999999500000000
i++ 1701 ++i 1611 foo 499999999500000000
i++ 1701 ++i 1610 foo 499999999500000000
i++ 1691 ++i 1610 foo 499999999500000000
i++ 1701 ++i 1600 foo 499999999500000000
i++ 1701 ++i 1610 foo 499999999500000000
i++ 1691 ++i 1610 foo 499999999500000000
i++ 1701 ++i 1610 foo 499999999500000000
i++ 1691 ++i 1610 foo 499999999500000000
i++ 1701 ++i 1610 foo 499999999500000000
i++ 1701 ++i 1610 foo 499999999500000000
i++ 1701 ++i 1610 foo 499999999500000000
i++ 1692 ++i 1610 foo 499999999500000000
i++ 1701 ++i 1610 foo 499999999500000000
i++ 1691 ++i 1610 foo 499999999500000000
在Java中,不存在这样的区别。 Java虚拟机解释代码,无论你写++i还是i ++,都将转换为相同的指令集的字节码。
但是在C / C ++中存在巨大的差异,如果你不使用任何优化标志,那么你的循环速度可能会慢到3倍。
使用像-O / -O3这样的优化标志将强制编译器使输出汇编代码更简单(在大多数情况下),因此更快(在大多数情况下)。
不,完全没有任何区别。
这来自C ++,但即使在那里,在这种情况下也没有任何区别。当i是一个对象时,有区别之处是i ++必须创建该对象的另一个副本,因为它必须返回项目的原始未更改值,而++ i可以返回已更改的对象,因此节省了一个副本。
在使用用户定义对象的C ++中,复制的成本可能很高,因此值得记住。由于这个原因,人们倾向于在int变量中使用它,因为无论如何它都一样好...
不会更快。编译器和带有JIT的JVM将轻松处理这种微不足道的差异。
如果适用,您可以使用常规循环优化技术来获得速度优势,例如展开。
iinc
),因为增量表达式的结果并没有被直接使用。for (int i = 0; i < max; i += 1) {
something
}
* 已使用Eclipse编译器测试