除非使用System.out.println,否则看似无限循环终止

时间:2017-02-01 04:49:06

标签: 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);

但是按原样,它打印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是否认识到它是无限循环并在第一种情况下跳过它但是必须在第二种情况下执行方法调用,以便它按预期运行? 困惑:))

6 个答案:

答案 0 :(得分:159)

这两个例子都不是无穷无尽的。

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

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

正如讨论中所提到的,时间将在很大程度上取决于OS如何缓冲输出,是否输出到终端仿真器等,因此它可能远高于几分钟。

答案 1 :(得分:33)

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

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

答案 2 :(得分:13)

这可能有两个原因:

  1. Java优化x循环,因为循环后没有使用System.out.println(x);,只需删除循环。您可以通过在循环后放置x语句来检查这一点。

  2. Java实际上可能没有优化循环,并且它正在正确执行程序,最终int对于x和溢出来说会变得太大。整数溢出很可能使整数y为负,它将小于j,因此它将从循环中出来并打印System.out.println(x);的值。这也可以通过在循环后添加function initRTCMultiConnection(userid) { var connection = new RTCMultiConnection(); connection.body = document.getElementById('videos-container'); connection.channel = connection.sessionid = connection.userid = userid || connection.userid; connection.sdpConstraints.mandatory = { OfferToReceiveAudio: false, OfferToReceiveVideo: true }; var iceServers = []; iceServers.push({ url: 'stun:stun.l.google.com:19302' }); iceServers.push({ url: 'stun:stun.anyfirewall.com:3478' }); iceServers.push({ url: 'turn:turn.anyfirewall.com:443?transport=tcp', credential: 'webrtc', username: 'webrtc' }); connection.iceServers = iceServers; 来检查。

  3. 此外,即使在第一种情况下,最终会发生溢出,从而将其渲染到第二种情况,因此它永远不会是真正的无限循环。

答案 3 :(得分:1)

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

如果您正在寻找一个无限循环的例子, 它应该看起来像这样

tableView:heightForRowAtIndexPath:

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

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

int x = 6;

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

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

答案 4 :(得分:1)

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

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

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

答案 5 :(得分:0)

有趣的问题实际上在两种情况下循环都不是无穷无尽的

但它们之间的主要区别在于它将终止的时间以及x超过int的最大值2,147,483,647所需的时间,之后它将达到溢出状态并且循环将终止。

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

示例

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

输出:

finished!
BUILD SUCCESSFUL (total time: 0 seconds)

测试此无限循环后,终止时间不到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)

在这个测试用例中,你会注意到终止和完成程序运行所花费的时间差别很大。

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

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

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

我测试了这个案例:

联想2.7 GHz英特尔酷睿i5

操作系统:Windows 8.1 64x

IDE:NetBeans 8.2

完成该计划大约需要8小时(486分钟)。

另外,您可以注意到for循环i = i + 1中的步长增量是达到max int值的非常缓慢的因素。

我们可以更改此因子并使步骤增量更快,以便在更短的时间内测试循环。

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

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秒。

在此测试示例之后,我认为它应该澄清问题并证明Zbynek Vyskovsky - kvr000's answer的有效性,它也将回答question