看似无休止的循环终止,除非使用System.out.println

我有一个简单的代码应该是一个无尽的循环,因为x将永远在增长,并将永远比j更大。

 int x = 5; int y = 9; for (int j = 0; j < x; j++) { x = x + y; } System.out.println(y); 

但是现在,它打印y并且不会无休止地循环。 我无法弄清楚为什么。 但是,当我按以下方式调整代码时:

 int x = 5; int y = 9; for (int j = 0; j < x; j++) { x = x + y; System.out.println(y); } System.out.println(y); 

它变成了一个无限循环,我不知道为什么。 java是否认识到它是一个无限循环,在第一种情况下跳过它,但是必须在第二种情况下执行一个方法调用,所以它的行为如预期的那样? 困惑:)

这两个例子都不是无止境的。

问题是Java中inttypes的限制(或几乎任何其他通用语言)。 当x的值达到0x7fffffff ,增加任何正值将导致溢出, x变为负值,因此低于j

第一个和第二个循环之间的区别在于内部代码需要更多的时间,在x溢出之前可能需要几分钟的时间。 对于第一个示例,它可能需要less于第二个或最有可能的代码将被优化器删除,因为它没有任何作用。

正如在讨论中提到的,时间将很大程度上取决于操作系统如何缓冲输出,是否输出到terminal仿真器等,因此可以远高于几分钟。

由于它们被声明为int,所以一旦达到最大值,循环将会中断,因为x值将变为负值。

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

这可能有两个原因:

  1. Java优化了for循环,并且由于在循环之后没有使用x ,只需删除循环。 你可以通过把System.out.println(x); 循环后的语句。

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

而且,即使在第一种情况下,最终会发生溢出,从而将其呈现给第二种情况,所以它永远不会是一个真正的无限循环。

它们都不是无限循环,最初j = 0,只要j <x,j增加(j ++),j是一个整数,所以循环将运行,直到达到最大值,然后溢出(整数溢出是条件当算术运算的结果(例如乘法或加法)超过用于存储它的整数types的最大大小时)。 对于第二个例子,系统只打印y的值直到循环中断。

如果你正在寻找一个无限循环的例子,它应该是这样的

 int x = 6; for (int i = 0; x < 10; i++) { System.out.println("Still Looping"); } 

因为(x)永远不会达到10的值;

你也可以用double for循环创build一个无限循环:

 int i ; for (i = 0; i <= 10; i++) { for (i = 0; i <= 5; i++){ System.out.println("Repeat"); } } 

这个循环是无限的,因为第一个for循环说我<10,这是真的,所以它进入第二个循环,第二个循环增加(i)的值,直到它是== 5.然后进入第一个for循环,因为我<10,进程不断重复,因为它在第二个for循环之后重置

这是一个有限循环,因为一旦x的值超过2,147,483,647 (这是一个int的最大值), x将变成负数,不再大于j ,无论是否打印y。

您可以将y的值更改为100000并在循环中打印y ,循环将很快中断。

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

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

但是它们之间的主要区别是什么时候它将终止,并且x将花费多less时间来超过max int值,即2,147,483,647之后它将达到溢出状态并且循环将终止。

理解这个问题的最好方法就是testing一个简单的例子并保存其结果。

例如

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

输出:

 finished! BUILD SUCCESSFUL (total time: 0 seconds) 

在testing完这个无限循环之后,终止会花费不到1秒的时间。

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

输出:

 infinite: 314572809 infinite: 314572810 infinite: 314572811 . . . infinite: 2147483644 infinite: 2147483645 infinite: 2147483646 infinite: 2147483647 finished! BUILD SUCCESSFUL (total time: 486 minutes 25 seconds) 

在这个testing案例中,您将会注意到终止和完成程序运行所花费的时间的巨大差异。

如果你没有耐心,你会认为这个循环是无止境的,不会终止,但实际上它将花费数小时才能终止并达到i值的溢出状态。

最后,我们在for循环中放置print语句之后得出结论:在没有print语句的情况下,比第一个case中的循环花费更多的时间。

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

我testing这个案例:

联想2.7 GHz英特尔酷睿i5

操作系统:Windows 8.1 64x

IDE:NetBeans 8.2

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

你也可以注意到for循环i = i + 1中的步增量是达到max int值的非常慢的因子。

我们可以改变这个因素,使步进增量更快,以便在更短的时间内testing循环。

如果我们把i = i * 10和testing它:

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

输出:

 infinite: 100000 infinite: 1000000 infinite: 10000000 infinite: 100000000 infinite: 1000000000 infinite: 1410065408 infinite: 1215752192 finished! BUILD SUCCESSFUL (total time: 0 seconds) 

正如你所看到的,与前一个循环相比,速度非常快

终止并完成程序运行需要不到1秒的时间。

经过这个testing的例子,我认为它应该澄清问题,并certificateZbynek Vyskovsky – kvr000的答案的有效性,也将是这个问题的答案。