除非使用 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 是否认识到它是一个无穷无尽的循环,并在第一种情况下跳过它,但是在第二种情况下必须执行一个方法调用,这样它才能像预期的那样运行? 困惑:)

8606 次浏览

Both of the examples are not endless.

The issue is the limitation of int type in Java (or pretty much any other common language). When the value of x reaches 0x7fffffff, adding any positive value will result in overflow and the x becomes negative, therefore lower than j.

The difference between the first and second loop is that the inner code takes much more time and it would take probably several minutes until x overflows. For the first example it may take less than second or most probably the code will be removed by optimizer as it doesn't have any effect.

As mentioned in the discussion, the time will heavily depend on how OS buffers the output, whether it outputs to terminal emulator etc., so it can be much higher than few minutes.

There can be two reasons for this:

  1. Java optimizes the for loop and since there is no use of x after the loop, simply removes the loop. You can check this by putting System.out.println(x); statement after the loop.

  2. It may be possible that Java is not actually optimizing the loop and it is executing the program correctly and eventually x will grow too large for int and overflow. Integer overflow will most probably make the integer x as negative which will be smaller than j and so it will come out of the loop and print the value of y. This also can be checked by adding System.out.println(x); after the loop.

Also, even in the first case eventually overflow will happen thus rendering it to the second case so it will never be a true endless loop.

Since they are declared as int, once it reaches the max value, the loop will break as the x value will becomes negative.

But when the System.out.println is added to the loop, the speed of execution becomes visible (as outputting to console will slow down the execution speed). However, if you let the 2nd program (the one with syso inside the loop) runs for long enough, it should have the same behavior as the first one (the one without syso inside the loop).

They are both not endless loops, initially j = 0 , as long as j < x, j increases(j++), and j is an integer so the loop would run until it reaches the maximum value then overflow(An Integer Overflow is the condition that occurs when the result of an arithmetic operation, such as multiplication or addition, exceeds the maximum size of the integer type used to store it.). for the second example the system just prints the value of y until the loop breaks.

if you are looking for an example of an endless loop, it should look like this

int x = 6;


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

because (x) would never attain the value of 10;

you could also create an infinite loop with a double for loop:

int i ;


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

this loop is infinite because the first for loop says i < 10, which is true so it goes into the second for loop and the second for loop increases the value of (i) until it is == 5. Then it proceeds into the first for loop again because i < 10,the process keeps repeating itself because it resets after the second for loop

It's a finite loop because once the value of x exceeds 2,147,483,647 (which is the maximum value of an int), x will become negative and not greater than j any more, whether you print y or not.

You can just change the value of y to 100000 and print y in the loop and the loop will break very soon.

The reason why you feel it became infinite is that the System.out.println(y); made the code to be executed very much slower than without any actions.

Interesting problem Actually in both cases loop isn't endless

But the main difference between them is when it will terminate and how much time x will take to exceed max int value which is 2,147,483,647 after that it will reach overflow state and the loop will terminate.

Best way to understand this problem is to test a simple example and preserve its results.

Example:

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

Output:

finished!
BUILD SUCCESSFUL (total time: 0 seconds)

After testing this infinite loop it will take less than 1 second to terminate.

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

Output:

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

On this test case you will notice a huge difference in the time taken to terminate and finish running the program.

If you aren't patience you will think this loop is endless and won't terminate but in fact it will take hours to terminate and reach the overflow state at i value.

Finally we concluded after we put print statement inside for loop that it will take much more time than loop in the first case without print statement.

That time taken to run the program depends on your computer specifications in particular processing power(processor capacity), operating system and your IDE which is compiling the program.

I test this case on:

Lenovo 2.7 GHz Intel Core i5

OS : Windows 8.1 64x

IDE : NetBeans 8.2

It takes about 8 hours (486 minutes) to finish the program.

Also you can notice that the step increment in the for loop i = i + 1 is very slow factor to reach the max int value.

We can change this factor and make step increment more faster in order to test for loop in less time.

if we put i = i * 10 and test it:

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

Output:

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

As you see it's very fast comparing to the previous loop

it takes less than 1 second to terminate and finish running the program.

After this test example I think it should clarify the problem and proves validity of Zbynek Vyskovsky - kvr000's answer, also it will be answer to this question.