看似无休止的循环终止,除非使用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中int
types的限制(或几乎任何其他通用语言)。 当x
的值达到0x7fffffff
,增加任何正值将导致溢出, x
变为负值,因此低于j
。
第一个和第二个循环之间的区别在于内部代码需要更多的时间,在x
溢出之前可能需要几分钟的时间。 对于第一个示例,它可能需要less于第二个或最有可能的代码将被优化器删除,因为它没有任何作用。
正如在讨论中提到的,时间将很大程度上取决于操作系统如何缓冲输出,是否输出到terminal仿真器等,因此可以远高于几分钟。
由于它们被声明为int,所以一旦达到最大值,循环将会中断,因为x值将变为负值。
但是当System.out.println被添加到循环中时,执行速度变得可见(因为输出到控制台将会降低执行速度)。 但是,如果让第二个程序(循环内有syso的程序)运行足够长的时间,它应该具有与第一个程序(循环内没有syso的程序)相同的行为。
这可能有两个原因:
-
Java优化了
for
循环,并且由于在循环之后没有使用x
,只需删除循环。 你可以通过把System.out.println(x);
循环后的语句。 -
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的答案的有效性,也将是这个问题的答案。