请考虑以下java代码:
public int main() {
int i = 1111;
for (; rules(i) != true && i < Integer.MAX_VALUE; i++) {
//LOG.debug("Testing i: " + i);
}
System.out.println("The mystery number is: " + i);
return i;
}
protected boolean rules(int nb) {
//...
}我已经发现,即使for循环的连续值是true,当它的主体为空时,循环也将停止执行。
main的最终结果是错误的(i为16698,大约98%的时间,有时更高/更低)。
--如果我从循环体中取消对LOG语句的注释,则循环将继续运行,直到循环继续计算为false为止。
我使用的JVM是MacOS X VM1.6.0。
ps:完整的代码源代码+其单元测试可在这里获得:https://gist.github.com/dirtyhenry/5804130
更新:
更新2:
java -version返回:
java version "1.6.0_51"
Java(TM) SE Runtime Environment (build 1.6.0_51-b11-456-11M4508)
Java HotSpot(TM) 64-Bit Server VM (build 20.51-b01-456, mixed mode)发布于 2013-06-18 12:12:38
我看到了一些关于SO to循环优化的引用,只有在超过10000次迭代之后才会发生。也许这就是为什么“魔法数字”经常在16000左右?
这里有个很好的讨论
发布于 2013-08-15 10:19:53
我在这里有一个类似的问题:Near empty Java For-Loop acts strange --您应该尝试使用JVM1.7或尝试使用一个while循环:
public int main() {
int i = 1111;
while(i < Integer.MAX_VALUE){
if (!rules(i)) {
break;
}
i++
}
System.out.println("The mystery number is: " + i);
return i;
}发布于 2013-08-16 09:09:17
我用jdk 1.7.0_21测试了您的代码,它返回了与LOG.debug语句相同的结果,即942210。
int i = 0;
for( ; !rules(i) && i < Integer.MAX_VALUE ; i++ ){
//LOG.debug( "test " + i );
}
System.out.println( "i is " + i );我还打印出了两个版本的字节码(空循环)。
0: aload_0
1: invokespecial #3 // Method java/lang/Object."<init>":()V
4: iconst_0
5: istore_1
6: aload_0
7: iload_1
8: invokevirtual #4 // Method rules:(I)Z
11: ifne 26
14: iload_1
15: ldc #5 // int 2147483647
17: if_icmpge 26
20: iinc 1, 1
23: goto 6
26: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
29: new #7 // class java/lang/StringBuilder
32: dup
33: invokespecial #8 // Method java/lang/StringBuilder."<init>":()V
36: ldc #9 // String i is
38: invokevirtual #10 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
41: iload_1
42: invokevirtual #11 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
45: invokevirtual #12 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
48: invokevirtual #13 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
51: return 带调试打印输出的循环
0: aload_0
1: invokespecial #3 // Method java/lang/Object."<init>":()V
4: iconst_0
5: istore_1
6: aload_0
7: iload_1
8: invokevirtual #4 // Method rules:(I)Z
11: ifne 48
14: iload_1
15: ldc #5 // int 2147483647
17: if_icmpge 48
20: new #6 // class java/lang/StringBuilder
23: dup
24: invokespecial #7 // Method java/lang/StringBuilder."<init>":()V
27: ldc #8 // String test
29: invokevirtual #9 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
32: iload_1
33: invokevirtual #10 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
36: invokevirtual #11 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
39: invokestatic #12 // Method LOG.debug:(Ljava/lang/String;)V
42: iinc 1, 1
45: goto 6
48: getstatic #13 // Field java/lang/System.out:Ljava/io/PrintStream;
51: new #6 // class java/lang/StringBuilder
54: dup
55: invokespecial #7 // Method java/lang/StringBuilder."<init>":()V
58: ldc #14 // String i is
60: invokevirtual #9 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
63: iload_1
64: invokevirtual #10 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
67: invokevirtual #11 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
70: invokevirtual #15 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
73: return 如您所见,循环结构是相同的。20 - 39只是构造字符串并调用LOG.debug。
因此,这可能是jdk的问题。尝试1.7,它应该有效。
https://stackoverflow.com/questions/17166047
复制相似问题