How to compare two integer object? - java

Integer i = new Integer(0);
Integer j = new Integer(0);
while(i <= j && j <= i && i !=j ){
System.out.println(i);
}
Why does this while loop execute?
I understand that i != j. But separately, both i <= j and j <= i returns true. Why? And doesn't that mean that i == j? In that case the while loop shouldn't execute even once. But it goes for an infinite loop. Why is this so?

While == can be performed between two references (and is, when both sides are Integer), <= can't - so the compiler unboxes. So, your code is equivalent to:
while (i.intValue() <= j.intValue() &&
j.intValue() <= i.intValue() &&
i != j)
Now when i and j refer to different Integer objects with the same value, all of those conditions will be met - hence the loop keeps executing.

Try:
while(!i.equals(j))
You are comparing two integer objects with == rather than two primitive int values. That is to say, "Integer" is an object while int is a primitive value. Doing != on an object will return true for Integer(0) and Integer(0) because they are indeed not equal -> each has a separate location in memory.
The "new" operator allocates dynamic memory on the heap.
For == to work, you could change the type to int, as in:
int i = 0;
int j = 0;
This will compare the values directly.
If you use "Integer," another alternative is to use the .compareTo method, which will compare the value of the objects

== for objects, like a capital-I Integer, compares references. <= and >= will unbox the Integer objects and compare the values numerically, which is completely different.
Think of == and != in this case as completely unrelated to the values of the Integers.

"<=" is comparing the values while "!=" the references hence here all the cases are true hence it is going in infinite loop.

Related

How to check whether an int is within a range of values

In a particular if-else, I have to identify if a given value falls within a range. The condition part looks like this:
else if (a==2 && b.equalsIgnoreCase("line")
&& <<Here I need to search if c falls within a range>> && d)
where a is int, b is string, c is int and d is a boolean. Now if c falls within 1 to 8, the condition is true, else it is false. How can I do that?
I think you need you this condition for c
(c > 1 && c < 8) // 1 and 8 are exclusive
(c => 1 && c <= 8) // 1 and 8 are inclusive
Full sample
else if (a==2 && b.equalsIgnoreCase("line")
&& (c > 1 && c < 8) && d)
If you need to check if the values belongs to a set of values, you need to use a Set and then check if the c belongs to that or not. In your original question, it was mentioned as a range and thus the answer. Anyways, this is how you can check a value in a set.
Integer[] arr = {1,4,9,11,13};
Set<Integer> set = new HashSet<>(Arrays.asList(arr));
...
else if (a==2 && b.equalsIgnoreCase("line")
&& (set.contains(c)) && d)
Surprise surprise, it is c >= low && c <= high
To answer to the update, you'll need to employ a set
Set<Integer> validValues = new HashSet<Integer>();
validValues.add(1);
validValues.add(4);
validValues.add(9);
validValues.add(10);
validValues.add(19);
if (validValues.contains(currentVal)) {
// do stuff
}
To curb java's verbosity you may use Guava's immutable set:
Set<Integer> validValues = ImmutableSet.of(1, 4, 9, 10, 19);
Try like this, range1 and range2 are ranges from which you need to check b.
(c < range1 && c > range2) ? d=true : d=false;
You simply need to add:
c > 1 && c < 8
If you ever feel that your conditionals are getting too complicated I'd suggest creating Boolean methods that simplify them down a little. This is a very moderate case, but for example this range problem could be represented by:
public boolean inRange(int num)
{
return (num > 1 && num < 8);
}
Unfortunately, the only way to do it would be using if else statements (as far as I know). A switch statement does not accept conditional operators, and so would not work for that. As suggested by some others, you could use seperate methods, as the methods, would allow you to check if other values were in range as well. Instead of just for this value, however, you could go for something like
public Boolean inRange(int num, int lowBound, int topBound)
{
return (num > lowBound && num < topBound);
}
and just use it in your code like this
else if (a==2 && b.equalsIgnoreCase("line")
&& inBound(c, 1, 8) && d)
It does not look too messy, and will work (you'll need to decide whether it is inclusive or exclusive bounds though).
The reason for the changed method is that it could be used in other places as well, making it useful for range checking.

Why does (i<=j && j<=i && i!=j) evaluate to TRUE?

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?
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.
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 }.
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.
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.
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.
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
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.
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
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.
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 .

Integer i=3 vs Integer i= new Integer (3) [duplicate]

This question already has answers here:
Weird Integer boxing in Java
(12 answers)
Why are autoboxed Integers and .getClass() values ==-equal, not only .equals()-equal?
(4 answers)
Closed 9 years ago.
I am comparing 2 pieces of code. First
Integer i=3;
Integer j=3;
if(i==j)
System.out.println("i==j"); //prints i==j
Second,
Integer i=3;
Integer j=new Integer(3);
if(i==j)
System.out.println("i==j"); // does not print
I have doubt that in the first snippet why i==j is being printed? Shouldn't the references be different?
It's to do with how boxing works. From the JLS section 5.1.7:
If the value p being boxed is true, false, a byte, or a char in the range \u0000 to \u007f, or an int or short number between -128 and 127 (inclusive), then let r1 and r2 be the results of any two boxing conversions of p. It is always the case that r1 == r2.
Basically, a Java implementation must cache the boxed representations for suitably small values, and may cache more. The == operator is just comparing references, so it's specifically detecting whether the two variables refer to the same object. In the second code snippet they definitely won't, as new Integer(3) definitely isn't the same reference as any previously created one... it always creates a new object.
Due to the rules above, this code must always give the same result:
Integer x = 127;
Integer y = 127;
System.out.println(x == y); // Guarantee to print true
Whereas this could go either way:
Integer x = 128;
Integer y = 128;
System.out.println(x == y); // Might print true, might print false
Java pools integers between -128 and 127 and hence both the references are the same.
Integer i=3;
Integer j=3;
This results in autoboxing and 3 is converted to Integer 3. So for i is referring to an Integer object that is in constant pool, now when you do j=3, the same reference as that of i is assigned to j.
Whereas below code:
Integer j=new Integer(3);
always results in a new Integer creation, in heap. This is not pooled. And hence you see that both reference are referring to different objects. Which results in
Integer i=3;
Integer j=new Integer(3);
if(i==j)
System.out.println("i==j"); // **does not print**
Integer i=3;
Integer j=3;
if(i==j)System.out.println("i==j");
Here, 3 is being auto-boxed and hence i and j point to the same Integer.
Integer i=3;
Integer j=new Integer(3);
if(i==j)System.out.println("i==j"); // does not print
Here, i points to the auto-boxed Integer whereas j points to a new Integer and hence there references fail the equals == operator test.
But, here's some more food for thought.
Integer i=300;
Integer j=300;
if(i!=j)System.out.println("i!=j"); // prints i!=j
Why? Because, auto-boxing shares Integer instances between -128 to 127 only. This behaviour, however, may differ between different Java implementations.
I have doubt that in the first snippet why i==j is being printed?
Shouldn't the references be different?
Because,
Integer i=3;
Integer j=3;
are internally using Integer#valueOf() to perform autoBoxing . And oracle doc says about valueOf() method that:
Returns an Integer instance representing the specified int value. If a
new Integer instance is not required, this method should generally be
used in preference to the constructor Integer(int), as this method is
likely to yield significantly better space and time performance by
caching frequently requested values. This method will always cache
values in the range -128 to 127, inclusive, and may cache other values
outside of this range.
Since the value 3 is cached therefore, both variables i and j are referencing the same object. So, i==j is returning true. Integer#valueOf() uses flyweight pattern.
No they shouldn't, because java can use pre-fabricated Integer objects for small numbers when autoboxing.
Because in the second peice of code your first integer is being auto-boxed while the second is not.
This means a new Integer instance is being created on the fly. These 2 object instances are different. The equality check will return false there as the two instances are actually different pieces of memory.
Interpreter/JIT optimizer can put all 3's in same box. But if you force a "new" then you get another address.
Try
j=8; // after initialization of i and j
then see the j's address changed for first version.
In a similar fashion to strings, when autoboxing is used, such as in
Integer i = 3;
Integer j = 3;
Java can draw from a pool of prefabricated objects. In the case of j, there's already an Integer instance representing the value of 3 in the pool, so it draws from that. Thus, i and j point to the same thing, thus i == j.
In your second example, you're explicitly instantiating a new Integer object for j, so i and j point to different objects, thus i != j.
In Following Piece of Code:
Integer i=3;
Integer j=3;
if(i==j)
System.out.println("i==j");
Here, "==" compares reference with each other rather than the value.
So, Integer i and j both are referring to same reference in the memory.
while in Following Piece of Code:
Integer i=3;
Integer j=new Integer(3);
if(i==j)
System.out.println("i==j");
The reference to both values are changed because 'j' is newly created object/reference of Integer in memory while 'i' is just referring to a value.
Therefore, the output of 1st code is "i==j" and 2nd code does not have any output.
Hope this helps.

how to declare i and j to make it be an infinite loop?

while( i <= j && i >= j && i != j) {}
how to declare i and j to make it be an infinite loop ?
// it's an interview question I met.
it's asking what's the declarations of i and j, make it be always true.
And I cant make it out by declaring i and j as number types. What other types can meet it ?
Integer i=new Integer(1000);
Integer j=new Integer(1000);
System.out.println((i<=j)+" "+(i>=j)+" "+(i!=j));
i and j will be automatically unboxed to ints for <= and >=, but not for !=. i and j are different instances, but have the same int value. That's why all three comparisons will return true.
This works too ("on my machine"):
Integer a = 128, b = 128;
whereas this won't work:
Integer a = 127, b = 127;
Auto-boxing an int is syntactic sugar for a call to Integer.valueOf(int). This function uses a cache for values from -128 to 127, inclusive. It may cache other values, but in my case, it doesn't.
Thus, the assignment of 128 doesn't have a cache hit; it creates a new Integer instance with each auto-boxing operation, and the reference comparison a != b is true. The assignment of 127 has a cache hit, and the resulting Integer objects are really the same instance from the cache. So, the reference comparison a != b is false.
What I really want to point out is to beware of reference comparison with auto-boxing. A more likely real-world problem is that you expect a == b is true because they were assigned the same (auto-boxed) value, you run some unit tests that confirm your expectation, and then your code fails "in the wild" when some counter exceeds the upper limit of the cache. Fun times!
Any equal value of 'i' and 'j' will reveal true with the given statement, say:
Integer i = new Integer(1);
Integer j = new Integer(1);
while( i <= j && i >= j && i != j) {}
The magic is with used operator! In case of != operator the compiler takes the operands as objects(including their values) whereas in case of >= or <= the compiler takes the operands value only. Thus, the above statement returns true.

Why are these == but not `equals()`?

I'm a bit confused about the way Java treats == and equals() when it comes to int, Integer and other types of numbers. For example:
Integer X = 9000;
int x = 9000;
Short Y = 9000;
short y = 9000;
List<Boolean> results = new ArrayList<Boolean>();
// results.add(X == Y); DOES NOT COMPILE 1)
results.add(Y == 9000); // 2)
results.add(X == y); // 3)
results.add(X.equals(x)); // 4)
results.add(X.equals(Y)); // 5)
results.add(X.equals(y)); // 6)
System.out.println(results);
outputs (maybe you should make your guess first):
[true, true, true, false, false]
That X == Y does not compile is to be expected, being different objects.
I'm a little surprised that Y == 9 is true, given that 9 is by default an int, and given that 1) didn't even compile. Note that you can't put an int into a method expecting a Short, yet here they are equal.
This is surprising for the same reason as two, but it seems worse.
Not surprising, as x is autoboxed to and Integer.
Not surprising, as objects in different classes should not be equal().
What?? X == y is true but X.equals(y) is false? Shouldn't == always be stricter than equals()?
I'd appreciate it if anyone can help me make sense of this. For what reason do == and equals() behave this way?
Edit: I have changed 9 to 9000 to show that this behavior is not related to the any unusual ways that the integers from -128 to 127 behave.
2nd Edit: OK, if you think you understand this stuff, you should consider the following, just to make sure:
Integer X = 9000;
Integer Z = 9000;
short y = 9000;
List<Boolean> results = new ArrayList<Boolean>();
results.add(X == Z); // 1)
results.add(X == y); // 2)
results.add(X.equals(Z)); // 3)
results.add(X.equals(y)); // 4)
System.out.println(results);
outputs:
[false, true, true, false]
The reason, as best as I understand it:
Different instance, so different.
X unboxed, then same value, so equal.
Same value, so equal.
y cannot be boxed to an Integer so cannot be equal.
(small) Integer instances are cached, so the invariant x == y is holded for small instances (actually -127 +128, depends on JVM):
Integer a = 10;
Integer b = 10;
assert(a == b); // ok, same instance reused
a = 1024;
b = 1024;
assert(a == b); // fail, not the same instance....
assert(a.equals(b)); // but same _value_
EDIT
4) and 5) yield false because equals check types: X is an Integer whereas Y is a Short. This is the java.lang.Integer#equals method:
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
The reason for
X == y
being true has to do with binary numeric promotion. When at least one operand to the equality operator is convertible to a numeric type, the numeric equality operator is used. First, the first operand is unboxed. Then, both operands are converted to int.
While
X.equals(y)
is a normal function call. As has been mentioned, y will be autoboxed to a Short object. Integer.equals always returns false if the argument is not an Integer instance. This can be easily seen by inspecting the implementation.
One could argue that this is a design flaw.
The morale of the story:
Autoboxing/unboxing is confusing, as is type promotion. Together, they make for good riddles but horrendous code.
In practice, it seldom makes sense to use numeric types smaller than int, and I'm almost inclined to configure my eclipse compiler to flag all autoboxing and -unboxing as an error.
Your problem here is not only how it treats == but autoboxing... When you compare Y and 9 you are comparing two primitives that are equal, in the last two cases you get false simply because that's how equals work. Two objects are equal only if they are of the same kind and have the same value.
When you say in "X.equals(y)" you are telling it to do Integer.equals(Short) and looking at the implementation of Integer.equals() it will fail:
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
Because of autoboxing the last two will result in the same failure as they will both be passed in as Shorts.
Edit: Forgot one thing... In the case of results.add(X == y); it will unbox X and do (X.intValue() == y) which happens to be true as well as 9 == 9
This automatic conversion is called autoboxing.
I remember a good practice for overriding "equal(object obj)" is of first checking the type of the parameter passed in. So perhap this causes X.equals(Y) to be false. You might check the souce code to dig out the truth :)
A bit more detail on how autoboxing works and how "small" valued Integer objects are cached:
When a primitive int is autoboxed into an Integer, the compiler does that by replacing the code with a call to Integer.valueOf(...). So, the following:
Integer a = 10;
is replaced by the compiler with the following:
Integer a = Integer.valueOf(10);
The valueOf(...) method of class Integer maintains a cache that contains Integer objects for all values between -127 and 128. If you call valueOf(...) with a value that's in this range, the method returns a pre-existing object from the cache. If the value is outside the range, it returns a new Integer object initialized with the specified value. (If you want to know exactly how it works, lookup the file src.zip in your JDK installation directory, and look for the source code of class java.lang.Integer in it.)
Now, if you do this:
Integer a = 10;
Integer b = 10;
System.out.println(a == b);
you'll see that true is printed - but not because a and b have the same value, but because a and b are referring to the same Integer object, the object from the cache returned by Integer.valueOf(...).
If you change the values:
Integer a = 200;
Integer b = 200;
System.out.println(a == b);
then false is printed, because 200 is outside the range of the cache, and so a and b refer to two distinct Integer objects.
It's unfortunate that == is used for object equality for value types such as the wrapper classes and String in Java - it's counter-intuitive.
Java will convert an Integer into an int automatically, if needed. Same applies to Short. This feature is called autoboxing and autounboxing. You can read about it here.
It means that when you run the code:
int a = 5;
Integer b = a;
System.out.println(a == b);
Java converts it into:
int a = 5;
Integer b = new Integer(a);
System.out.println(a == b.valueOf());

Categories