JAVA:为什么以下无限循环会在没有任何错误/异常的情况下终止?

5

当我在eclipse中尝试一些东西时,惊讶地发现运行这段代码时,它会在没有任何错误/异常的情况下被终止。

public class Test {
    public static void main(String[] args) {
        for(int i = 2; i > 0; i++){
            int c = 0;
        }
    }
}

当他的代码持续执行时

public class Test {
    public static void main(String[] args) {
        for(int i = 2; i > 0; i++){
            int c = 0;
            System.out.println(c);
        }
    }
}

尽管两者都应该是无限循环永远运行。但第一个代码片段为什么会被终止?是否有我所忽略的东西?

1
我认为这里可能出现了整数溢出。 - nhouser9
1
是的,我认为在某个时候整数会变成负数。 - ave4496
仅仅因为第二个程序打印慢(IO),你就认为它是一个无限循环吗?如果你运行 int i = Integer.MAX_VALUE; i++,你知道会发生什么吗? - SMA
1
请耐心等待,两者都会结束,使用输出流(控制台)打印Integer.MAX_VALUE次需要一些时间。您只需达到正值的极限,然后下一个增量将给出负值。 - AxelH
2个回答

8
首先,这两个代码片段并不是无限循环,因为一旦i超过Integer.MAX_VALUE,它将变成负数。它们只需要很长时间才能运行。 第一个片段运行的时间要短得多,因为它不需要打印任何内容,并且编译器可能足够聪明,只需优化代码并消除循环,因为它什么也不做。
测试您的第一个代码片段,将System.out.println(System.currentTimeMillis());添加到循环之前和之后,我得到了:
1486539220248
1486539221124

即在1秒内运行。

稍微改变循环:

System.out.println (System.currentTimeMillis ());
for(int i = 2; i > 0; i++){
    int c = 0;
    if (i==Integer.MAX_VALUE)
        System.out.println (i);
}
System.out.println (System.currentTimeMillis ());

I got

1486539319309
2147483647
1486539319344

正如你所看到的,从 0 开始增加到 Integer.MAX_VALUE 只需不到 1 秒钟的时间,然后会发生溢出,循环终止。
如果在循环中添加更多的打印语句,则终止所需的时间将更长。例如:
System.out.println (System.currentTimeMillis ());
for(int i = 2; i > 0; i++){
    int c = 0;
    if (i % 100000000 == 0)
        System.out.println (i);
}
System.out.println (System.currentTimeMillis ());

输出:

1486539560318
100000000
200000000
300000000
400000000
500000000
600000000
700000000
800000000
900000000
1000000000
1100000000
1200000000
1300000000
1400000000
1500000000
1600000000
1700000000
1800000000
1900000000
2000000000
2100000000
1486539563232

现在需要花费3秒钟。

3

重点是:这个循环没有任何可见的副作用。

因此,可以假设编译器正在优化整个循环。另一方面,javac并不以进行大量优化而闻名。因此:让我们看看会发生什么:

javap -c Test

...

public static void main(java.lang.String[]);

   0: iconst_2      
   1: istore_1      
   2: iload_1       
   3: ifle          14
   6: iconst_0      
   7: istore_2      
   8: iinc          1, 1
  11: goto          2
  14: return        

显然:循环仍然存在。因此,真正的问题是:在某个点上,由于int溢出,您的循环停止;而您的程序的第一个版本只是更快地到达了那个点(out.println()是一个非常昂贵的操作;与纯加法相比)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接