Java 除非使用System.out.println,否则看似无止境的循环将终止

Java 除非使用System.out.println,否则看似无止境的循环将终止,java,for-loop,infinite-loop,Java,For Loop,Infinite Loop,我有一段简单的代码,它被认为是一个无止境的循环,因为x总是在增长,并且总是比j大 int x = 5; int y = 9; for (int j = 0; j < x; j++) { x = x + y; } System.out.println(y); 它变成了一个无止境的循环,我不知道为什么。java是否认识到它是一个无止境的循环,并在第一种情况下跳过它,但在第二种情况下必须执行一个方法调用,以使其行为符合预期? 困惑:)这两个例子并非无穷无尽 问题在于Java(或几乎任何其

我有一段简单的代码,它被认为是一个无止境的循环,因为
x
总是在增长,并且总是比
j

int x = 5;
int y = 9;
for (int j = 0; j < x; j++) {
   x = x + y;
}
System.out.println(y);
它变成了一个无止境的循环,我不知道为什么。java是否认识到它是一个无止境的循环,并在第一种情况下跳过它,但在第二种情况下必须执行一个方法调用,以使其行为符合预期?
困惑:)

这两个例子并非无穷无尽

问题在于Java(或几乎任何其他公共语言)中
int
类型的限制。当
x
的值达到
0x7fffffff
时,添加任何正值都将导致溢出,
x
变为负值,因此低于
j

第一个循环和第二个循环之间的区别是,内部代码需要更多的时间,并且可能需要几分钟,直到
x
溢出。对于第一个示例,它可能需要不到一秒钟的时间,或者很可能优化器会删除代码,因为它没有任何效果


正如讨论中提到的,时间在很大程度上取决于操作系统缓冲输出的方式、是否输出到终端仿真器等,因此时间可能比几分钟高出很多。

原因可能有两个:

  • Java为循环优化了
    ,因为循环之后没有使用
    x
    ,所以只需删除循环即可。您可以通过放入
    System.out.println(x)来检查这一点语句

  • 有可能Java实际上并没有优化循环,而是正确地执行程序,最终
    x
    对于
    int
    和溢出来说会变得太大。整数溢出很可能使整数
    x
    为负值,该值小于j,因此它将从循环中出来并打印
    y
    的值。这也可以通过添加
    System.out.println(x)来检查在循环之后


  • 此外,即使在第一种情况下,最终也会发生溢出,从而使其进入第二种情况,因此它永远不会是真正的无止境循环。

    因为它们被声明为int,一旦达到最大值,循环将随着x值变为负值而中断


    但是当System.out.println添加到循环中时,执行速度变得可见(因为输出到控制台会降低执行速度)。但是,如果让第二个程序(循环中有syso的程序)运行足够长的时间,它应该与第一个程序(循环中没有syso的程序)具有相同的行为

    它们都不是无止境的循环, 最初j=0,只要j 如果你想找一个无止境循环的例子, 应该是这样的

    int x = 6;
    
    for (int i = 0; x < 10; i++) {
    System.out.println("Still Looping");
    }
    
    intx=6;
    对于(int i=0;x<10;i++){
    System.out.println(“仍然循环”);
    }
    
    因为(x)永远不会达到10的值

    您还可以使用双for循环创建无限循环:

    int i ;
    
      for (i = 0; i <= 10; i++) {
          for (i = 0; i <= 5; i++){
             System.out.println("Repeat");   
          }
     }
    
    inti;
    
    对于(i=0;i这是一个有限循环,因为一旦
    x
    的值超过
    2147483647
    (这是
    int
    的最大值),
    x
    将变为负值,不再大于
    j
    ,无论是否打印y

    您只需将
    y
    的值更改为
    100000
    ,然后在循环中打印
    y
    ,循环很快就会中断


    您觉得它变得无限的原因是
    System.out.println(y);
    使得代码的执行速度比不执行任何操作要慢得多。

    有趣的问题实际上,在这两种情况下,循环并不是无止境的

    但它们之间的主要区别在于它何时终止,以及超过max
    int
    值所需的时间
    x
    ,该值为
    2147483647
    ,之后它将达到溢出状态,循环将终止

    理解这个问题的最佳方法是测试一个简单的示例并保存其结果

    示例

    for(int i = 10; i > 0; i++) {}
    System.out.println("finished!");
    
    输出:

    finished!
    BUILD SUCCESSFUL (total time: 0 seconds)
    
    infinite: 314572809
    infinite: 314572810
    infinite: 314572811
    .
    .
    .
    infinite: 2147483644
    infinite: 2147483645
    infinite: 2147483646
    infinite: 2147483647
    finished!
    BUILD SUCCESSFUL (total time: 486 minutes 25 seconds)
    
    infinite: 100000
    infinite: 1000000
    infinite: 10000000
    infinite: 100000000
    infinite: 1000000000
    infinite: 1410065408
    infinite: 1215752192
    finished!
    BUILD SUCCESSFUL (total time: 0 seconds)
    
    在测试这个无限循环之后,将花费不到1秒的时间来终止

    for(int i = 10; i > 0; i++) {
        System.out.println("infinite: " + i);
    }
    System.out.println("finished!");
    
    输出:

    finished!
    BUILD SUCCESSFUL (total time: 0 seconds)
    
    infinite: 314572809
    infinite: 314572810
    infinite: 314572811
    .
    .
    .
    infinite: 2147483644
    infinite: 2147483645
    infinite: 2147483646
    infinite: 2147483647
    finished!
    BUILD SUCCESSFUL (total time: 486 minutes 25 seconds)
    
    infinite: 100000
    infinite: 1000000
    infinite: 10000000
    infinite: 100000000
    infinite: 1000000000
    infinite: 1410065408
    infinite: 1215752192
    finished!
    BUILD SUCCESSFUL (total time: 0 seconds)
    
    在这个测试用例中,您将注意到终止和完成运行程序所花费的时间有很大的不同

    如果您没有耐心,您会认为此循环是无止境的,不会终止,但事实上,终止并达到
    i
    值的溢出状态需要数小时

    最后,我们在for循环中放入print语句后得出结论,在没有print语句的第一种情况下,这将比循环花费更多的时间

    运行程序所需的时间取决于您的计算机规格,特别是处理能力(处理器容量)、操作系统和编译程序的IDE

    我在以下方面测试此案例:

    联想2.7 GHz英特尔酷睿i5

    OS:Windows 8.1 64x

    IDE:NetBeans 8.2

    大约需要8小时(486分钟)才能完成该程序

    您还可以注意到for循环
    i=i+1
    中的步长增量对于达到最大int值来说是非常缓慢的

    我们可以改变这个因子,使步长增加得更快,以便在更短的时间内测试循环

    如果我们放置
    i=i*10
    并测试它:

    for(int i = 10; i > 0; i*=10) {
               System.out.println("infinite: " + i);
    }
         System.out.println("finished!");
    
    输出:

    finished!
    BUILD SUCCESSFUL (total time: 0 seconds)
    
    infinite: 314572809
    infinite: 314572810
    infinite: 314572811
    .
    .
    .
    infinite: 2147483644
    infinite: 2147483645
    infinite: 2147483646
    infinite: 2147483647
    finished!
    BUILD SUCCESSFUL (total time: 486 minutes 25 seconds)
    
    infinite: 100000
    infinite: 1000000
    infinite: 10000000
    infinite: 100000000
    infinite: 1000000000
    infinite: 1410065408
    infinite: 1215752192
    finished!
    BUILD SUCCESSFUL (total time: 0 seconds)
    
    如您所见,与上一个循环相比,它非常快

    终止并完成运行t不到1秒