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
溢出。对于第一个示例,它可能需要不到一秒钟的时间,或者很可能优化器会删除代码,因为它没有任何效果
正如讨论中提到的,时间在很大程度上取决于操作系统缓冲输出的方式、是否输出到终端仿真器等,因此时间可能比几分钟高出很多。原因可能有两个:
,因为循环之后没有使用x
,所以只需删除循环即可。您可以通过放入System.out.println(x)来检查这一点循环后的代码>语句
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);
使得代码的执行速度比不执行任何操作要慢得多。有趣的问题实际上,在这两种情况下,循环并不是无止境的
但它们之间的主要区别在于它何时终止,以及超过maxint
值所需的时间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秒