Reputation: 148
I use the in
operator in groovy very much. But now I found an odd behavior.
See the following script.
int x = 1
long y = 1
println "x == y " + (x == y) // true
println "x == new Long(y) " + (x == new Long(y)) // true
println "x in [y] " + (x in [y]) // false Why?
println "[y].contains(x) " + [y].contains(x) // false Why?
The in
operator or the contains()
return false
, although the two numbers are equal. But why?
I've learned that a collection can't contain primitive types, but x == new Long(y)
is true.
Upvotes: 1
Views: 69
Reputation: 10665
Why it is not working?
Because x
is int
and y
is long
.
Why (x == y) returns true?
The ==
operator uses type casting behind so (x == y)
is same as:
(x == (int)y)
When you create a list in groovy using []
syntax groovy uses the ArrayList
class behind. So the in
and contains()
method returns depend on the contains()
method implementaion:
public boolean contains(Object o) {
return indexOf(o) >= 0;
}
As you can see it calls indexOf
method:
public int indexOf(Object o) {
if (o == null) {
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
} else {
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
and the indexOf
method actually depends on the equals method implementation of the object passed.
So when you say [y].contains(x)
or x in [y]
it will use Integer
's equals()
method implementation:
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
As you can see it will return false
if you are not passing an int
regardless of the actual value.
if say [x].contains(y)
or y in [x]
it will use Long
's equals method implementation:
public boolean equals(Object obj) {
if (obj instanceof Long) {
return value == ((Long)obj).longValue();
}
return false;
}
which again returns false
if the argument is not instance of long
regardless of the value.
As further example this code should return false:
int x = 1
long y = 1
x.equals(y)
Upvotes: 3