106

I have written a piece of Java code which is running in an infinite loop.

Below is the code:

public class TestProgram {
    public static void main(String[] args){
        Integer i = new Integer(0);
        Integer j = new Integer(0);

        while(i<=j && j<=i && i!=j){
            System.out.println(i);
        }
    }
}

In the code above, while seeing the condition in the while loop, at first it looks like that program will not go inside the while loop. But actually it is an infinite loop and keeps printing the value.

What is happening here?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Kshitij Jain
  • 1,793
  • 5
  • 19
  • 30
  • 8
    Simple answer is `i<=j && j<=i && i!=j` this condition always evaluates to true. Just take a piece of paper and evaluate you will catch it :) – Pradeep Simha Sep 14 '13 at 17:44
  • 4
    The way you are creating integer is incorrect. Use 'compareTo' – nachokk Sep 14 '13 at 17:44
  • 7
    If you never change `i` or `j`, when would you expect the loop to terminate? – Fred Larson Sep 14 '13 at 17:44
  • 33
    @PradeepSimha For simple int values, this would always yield *false*. From `i<=j` and `j<=i` you can conclude, that `i == j`, which contradicts the last term. Thus the whole expression evaluates to false and the while would not be entered. Key point is the object identity here! – Sirko Sep 14 '13 at 17:48
  • 1
    Is there a **point** to the Integer cache? – Cole Tobin Sep 17 '13 at 23:55
  • 4
    As an aside, this is puzzle 32 in the book Java Puzzlers: Traps, Pitfalls, and Corner Cases. – Cyanfish Sep 19 '13 at 15:48
  • @nachokk By that you mean `Integer.valueOf()`, right? AFAIK, `compareTo()` does not return `Integer`s, but rather `int`s, and is for _comparing_, not obtaining instances. – AJMansfield Sep 20 '13 at 15:08
  • @AJMansfield They are 2 sentences may be my english is not good. First sentence is what you point. Second sentence `compareTo` to compare objects with their natural order rather than using `i<=j` etc.. – nachokk Sep 20 '13 at 15:16
  • possible duplicate of [When comparing two Integers in Java does auto-unboxing occur?](http://stackoverflow.com/questions/1514910/when-comparing-two-integers-in-java-does-auto-unboxing-occur) – Audrius Meškauskas Apr 03 '14 at 11:46
  • Another way of framing this puzzle "In Java, will the condition i<=j && j<=i && i!=j ever evaluate to true?" – JavaHopper Jun 02 '16 at 15:04

10 Answers10

189
  • i <= j is evaluated to true, because auto unboxing happens for int comparisons and then both i and j hold the default value, 0.

  • j <= i is evaluated to true because of the above reason.

  • i != j is evaluated to true, because both i and j are different objects. And while comparing objects, there isn't any need of auto unboxing.

All the conditions are true, and you are not changing i and j in loop, so it is running infinitely.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Juned Ahsan
  • 67,789
  • 12
  • 98
  • 136
  • 10
    can you please explain, why != is checking for the memory index of reference objects and <= is checking for the un-boxed value of Integer ??.. why there is such difference between these operator ? – Punith Raj Sep 14 '13 at 18:02
  • 41
    @PunithRaj < & > operators work on primitives and not on objects, hence the auto unboxing happens for these operators. But == and != operators can be used for objects comparison also so no need of unboxing here, hence objects are compared. – Juned Ahsan Sep 14 '13 at 18:05
  • 14
    Ah, the hidden dangers of implicit boxing/unboxing!! – Hot Licks Sep 14 '13 at 23:13
  • 3
    Stack Overflow should just add a new tag, "Auto-unboxing was the biggest mistake ever made in Java". :-). Except for writers of the Java Puzzler books. Use it to tag questions like these. – user949300 Sep 15 '13 at 03:30
  • 1
    @user949300 It's not a mistake, it's useful in many contexts. – arshajii Sep 15 '13 at 14:00
  • 1
    @arshajii other than saving typing "intValue()", where have you found unboxing to be very useful? I mainly find it confusing. For the record, I think autoboxing is o.k. and often very useful. – user949300 Sep 15 '13 at 17:33
  • 4
    note that `Integer.valueOf(0) == Integer.valueOf(0)` is always evaluated to true because in this case the same object is returned (see IntegerCache http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/Integer.java#Integer.IntegerCache) – Vitalii Fedorenko Sep 15 '13 at 18:13
  • @user949300 There are times when you explicitly need to use the wrapper classes instead of primitives (e.g. if you need to support a `null` value). In such cases, auto unboxing allows you to use these variables with regular arithmetic operations, e.g. `a + b` where `a` and `b` are `Integer`s. I find this to be convenient. – arshajii Sep 16 '13 at 23:07
  • 1
    @arshajii If you need to support a null value, then doing math "conveniently" is a poor idea. – user949300 Sep 17 '13 at 04:34
  • @VitaliiFedorenko the spec only guarantees this behaviour for numbers in range `[128,-127]`, so don't count on it in general http://docs.oracle.com/javase/7/docs/api/java/lang/Integer.html#valueOf%28int%29 – pwes Sep 18 '13 at 09:23
  • @pwes right, that's what the [line 576](http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/Integer.java#576) says: `Integer cache[] = new Integer[-(-128) + 127 + 1];` – Vitalii Fedorenko Sep 18 '13 at 10:36
  • @VitaliiFedorenko you must distinguish between the code and the docs. The implementation is a subject to change, the java.lang API, and hence the JavaDocs, is the official part of Java standard. – pwes Sep 19 '13 at 11:28
  • 1
    A classic example of C# really helping you dodge insanity like this with structs, overriding of Equals and operator overloading. You'd have to go way out of your way to end up in this confused place Java leaves you. – Chris Moschini Sep 20 '13 at 05:45
  • @user949300 I'd rather say the big mistake here is that == (or !=, for that matter) does not call equals. If object identity was a different operator, that wouldn't be as confusing as well. – Dr. Hans-Peter Störr Sep 20 '13 at 18:39
41

Because you are comparing

  • 0 < = 0 (true) // unboxing

  • 0 > = 0 (true) // unboxing

  • reference != secondReference (true) as you are creating objects, not a primitive comparison. So it evaluates to while(true) { // Never ending loop }.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Ashwani
  • 3,463
  • 1
  • 24
  • 31
17

The integer objects are different. It is different from the basic int type.

See this answer: How to properly compare two Integers in Java?

The i != j part is true, which you were expecting to be false.

Community
  • 1
  • 1
Colonel Panic
  • 1,604
  • 2
  • 20
  • 31
  • While true, it doesn't matter here nor does it answer the question. – Kon Sep 14 '13 at 17:45
  • 6
    @Kon: In fact this is the answer. Conditions #1 and #2 evaluate to `true` because of autoboxing. In case of #3 autoboxing does not apply and comparison takes place on object (memory location) level. – home Sep 14 '13 at 17:47
2

There are two different cases which we have to understand first,

case 1:

        Integer i = new Integer(10);
        Integer j = new Integer(10);

        System.out.println((i<=j && j<=i && i!=j));
        System.out.println(i!=j);

case 2:

        Integer i = 10;
        Integer j = 10;

        System.out.println((i<=j && j<=i && i==j));
        System.out.println(i==j);

both are different, as

in case 1: i!=j will be true because both referencing to two different object in heap and can't be same. But

in case 2: i==j will be true because both 10 are integer literals and Java maintains pool for Integer literals which have value (-128 <= X <= 127). So, in this case 10<=127 results true, So both will have reference to same object.

Akhilesh Dhar Dubey
  • 2,152
  • 2
  • 25
  • 39
1

The loop is not ending because your condition is true( i != j is true because there are 2 different objects, use Integer.valueOf instead) and inside the loop the values are not changing so your condition remains true forever.

Silviu Burcea
  • 5,103
  • 1
  • 29
  • 43
1

Perhaps the reason is that both 'i' and 'j' are objects, and object comparison is not the same as object reference comparison. Please consider using !i.equals(j) instead of i!=j

Eric Gopak
  • 1,663
  • 1
  • 13
  • 26
1

The integer objects are different. It is different from the basic int type. so you can just do like that. what you do it's just compare the object and of course the result is true.

Krichevskoy
  • 254
  • 2
  • 17
1

Integer a = new Integer(0); Integer b = new Integer(0);

The <= and >= comparisons will use the unboxed value 0, while the != will compare the references and will succeed since they are different objects.

Even this will also works i,e

Integer a = 1000; Integer b = 1000;

but this doesnot :

Integer a = 100; Integer b = 100;

The reason is because Integer internally uses caching for Integer objects between -128 and 127 and return instances from that cache for the range it covers. I am not sure but I guess you can also change its maximum value in package "java.lang.Integer.IntegerCache.high".

For better understanding check url : https://www.owasp.org/index.php/Java_gotchas#Immutable_Objects_.2F_Wrapper_Class_Caching

Waheed
  • 1,835
  • 15
  • 21
0

The program keeps on displaying the same value of i because you aren't incrementing or decrementing either the value of i or j. The condition in the for always keeps evaluating to true, so it is an infinite loop.

Soravux
  • 9,653
  • 2
  • 27
  • 25
  • I think the question was more about the `i!=j` part which surprisingly evaluates to true and not the `<=` comparisons. – Soravux Sep 15 '13 at 02:46
-3

you have to know its a bit different in && this and this & when you use && then when first condition is true then it check second condition if its false then it not checked third condition because in & operator if one condition is false all of the statement is false if use || then if it see true then it return true in your code because i and j is equal first and second condition are true then in third condition it will be false because they are equal and while condition is false .

sara Sodagari
  • 423
  • 1
  • 9
  • 23
  • i don't know why my answer get mines value because my answer is true see this link its true then before get mines to my answer read more http://stackoverflow.com/questions/5564410/difference-between-and – sara Sodagari Nov 20 '13 at 05:45