Groovy's .equals() method uses .compareTo() under the hood.
Today a colleague of mine shared a curious observation. He found out
that .equals()
(or ==
) in Groovy does something different from
what we would expect in Java. Oddly enough, it uses compareTo()
method
under the hood. I’ve made some code samples. Let’s look at them.
Test case:
- We have a class with some
Long
identifier field calledid
. - The class implements
Comparable
interface andcompareTo()
compares theid
values. - We have two instances of this class with
id = 1
. - The expected behaviour is that first instance is not equal to the second one.
Java example:
@Test
public void testEquals() {
System.out.println("Test is started.");
final MyClass first = new MyClass(1L);
final MyClass second = new MyClass(1L);
Assert.assertTrue(!first.equals(second));
Assert.assertTrue(first != second);
System.out.println("Test is finished.");
}
final class MyClass implements Comparable<MyClass> {
private final Long id;
MyClass(final Long id) {
this.id = id;
}
public int compareTo(MyClass o) {
System.out.println("MyClass.compareTo");
return this.id.compareTo(o.id);
}
}
The output is:
Test is started.
Test is finished.
The same example in Groovy(I’m using Grails 2.5.5 + JUnit 3 for testing):
void testEquals() {
println "Test is started."
final first = new MyClass(1)
final second = new MyClass(1)
assertTrue(!first.equals(second))
assertTrue(first != second)
println "Test is finished."
}
final class MyClass implements Comparable<MyClass> {
private final Long id
MyClass(final Long id) {
this.id = id
}
int compareTo(MyClass o) {
println "MyClass.compareTo"
return this.id <=> o.id
}
}
The output is:
--Output from testEquals--
Test is started.
MyClass.compareTo
| Failure: testEquals()
| junit.framework.AssertionFailedError
The odd things are:
MyClass.compareTo()
was called.- As a result, both expressions:
assertTrue(!first.equals(second))
andassertTrue(first != second)
fail.
I do not want to write any conclusion there, because I didn’t investigate the problem in details. It’s just a curious fact that I want to share with you. I’m not even sure is it a desired behaviour or just a bug. Share your thoughts in comments.
Keep on coding and be careful using Groovy! :)