3

It's written in all decent java courses, that if you implement the Comparable interface, you should (in most cases) also override the equals method to match its behavior.

Unfortunately, in my current organization people try to convince me to do exactly the opposite. I am looking for the most convincing code example to show them all the evil that will happen.

bvdb
  • 22,839
  • 10
  • 110
  • 123
  • 1
    Possible duplicate of [java.lang.Comparable and equals](http://stackoverflow.com/questions/6970879/java-lang-comparable-and-equals) – Moritz Petersen Oct 12 '16 at 08:19

4 Answers4

6

I think you can beat them by showing the Comparable javadoc that says:

It is strongly recommended (though not required) that natural orderings be consistent with equals. This is so because sorted sets (and sorted maps) without explicit comparators behave "strangely" when they are used with elements (or keys) whose natural ordering is inconsistent with equals. In particular, such a sorted set (or sorted map) violates the general contract for set (or map), which is defined in terms of the equals method.

For example, if one adds two keys a and b such that (!a.equals(b) && a.compareTo(b) == 0) to a sorted set that does not use an explicit comparator, the second add operation returns false (and the size of the sorted set does not increase) because a and b are equivalent from the sorted set's perspective.

So especially with SortedSet (and SortedMap) if the compareTo method returns 0, it assumes it as equal and doesn't add that element second time even the the equals method returns false, and causes confusion as specified in the SortedSet javadoc

Note that the ordering maintained by a sorted set (whether or not an explicit comparator is provided) must be consistent with equals if the sorted set is to correctly implement the Set interface. (See the Comparable interface or Comparator interface for a precise definition of consistent with equals.) This is so because the Set interface is defined in terms of the equals operation, but a sorted set performs all element comparisons using its compareTo (or compare) method, so two elements that are deemed equal by this method are, from the standpoint of the sorted set, equal. The behavior of a sorted set is well-defined even if its ordering is inconsistent with equals; it just fails to obey the general contract of the Set interface.

  • Once forgot to override the equals method, and to debug this intermittent problem was not nice. – Viktor Mellgren Oct 12 '16 at 08:50
  • Good quotes, however, I think your comments about `SortedSet` interface is not correct. (It's the other way round) e.g. a `TreeSet` (which is a `SortedSet`) can contain 2 objects `a` and `b` even when `a.equals(b) == true`. – bvdb Oct 12 '16 at 11:05
  • @bvdb I believe I got it right. The javadoc for Comparable interface does say that `For example, if one adds two keys a and b such that (!a.equals(b) && a.compareTo(b) == 0) to a sorted set that does not use an explicit comparator, the second add operation returns false (and the size of the sorted set does not increase) because a and b are equivalent from the sorted set's perspective.` – Madhusudana Reddy Sunnapu Oct 12 '16 at 12:44
5

If you don't override the equals method, it inherits its behaviour from the Object class.
This method returns true if and only if the specified object is not null and refers to the same instance.

Suppose the following class:

class VeryStupid implements Comparable
{
  public int x;

  @Override
  public int compareTo(VeryStupid o)
  {
    if (o != null)
      return (x - o.x);
    else
      return (1);
  }
}

We create 2 instances:

VeryStupid one = new VeryStupid();
VeryStupid two = new VeryStupid();
one.x = 3;
two.x = 3;

The call to one.compareTo(two) returns 0 indicating the instances are equal but the call to one.equals(two) returns false indicating they're not equal.
This is inconsistent.

Robert Kock
  • 5,795
  • 1
  • 12
  • 20
1

Consistency of compareTo and equals is not required but strongly recommended.

I'll give it a shot with this example:

private static class Foo implements Comparable<Foo> {
    @Override
    public boolean equals(Object _other) {
        System.out.println("equals");
        return super.equals(_other);
    }
    @Override
    public int compareTo(Foo _other) {
        System.out.println("compareTo");
        return 0;
    }
}
public static void main (String[] args) {
    Foo a, b;

    a = new Foo();
    b = new Foo();

    a.compareTo(b);  // prints 'compareTo', returns 0 => equal
    a.equals(b);     // just prints 'equals', returns false => not equal 
}

You can see that your (maybe very important and complicated) comparission code is ignored when you use the default equals-method.

lupz
  • 3,620
  • 2
  • 27
  • 43
  • 1
    Well you have an example on that are not related, but you don't describe why it is important that they are implemented the same way. – Viktor Mellgren Oct 12 '16 at 08:48
0

the method int compareTo(T o) allow you know if the T o is (in some way) superior or inferior of this, so it allow you to order a list of T o. In the scenario of int compareTo(T o) you have to do :

  • is o InstanceOfThis ? => true/false ;
  • is o EqualOfThis ? => true/false ;
  • is o SuperiorOfThis ? => true/false ;
  • is o InferiorOfThis ? true/false ;

So you see you have the equality test, and the best way to not implement the equality two times is to put it in the boolean equals(Object obj) method.

Zorglube
  • 664
  • 1
  • 7
  • 15