JAVA:为什么以下无限循环终止而没有任何错误/异常

时间:2017-02-08 07:27:32

标签: java infinite-loop

我正在弄乱日食中的东西,令我惊讶的是,我发现这段代码在运行时被终止而没有任何错误/异常

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);
        }
    }
}

尽管两者都应该是永无止境的无限循环。是否有一些我不知道为什么第一个代码片段被终止?

2 个答案:

答案 0 :(得分:8)

首先,两个片段都不是无限循环,因为i一旦通过Integer.MAX_VALUE就会变为负片。他们只需要很长时间才能运行。 第一个代码片段运行时间要少得多,因为它不需要打印任何内容,并且编译器可能足够聪明,只需优化代码并消除循环,因为它什么都不做。 / p>

测试你的第一个片段,在循环之前和之后添加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 ());

我得到了

1486539319309
2147483647
1486539319344

正如您所看到的,从i增加到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秒钟。

答案 1 :(得分:3)

关键是:此循环没有任何可见的副作用。

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

  

javap -c测试

     

...

     

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()是一个非常昂贵的操作;与纯数字添加相比)