Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Technique to automatically check consistency of equals, hashCode, and compareTo?

Tags:

I'm well aware of the contractual needs to make sure that hashCode is consistent with equals and that equals is consistent with compareTo. However, this is often violated in practice. Are there any tools, techniques, or libraries that can test for this consistency automatically?

I suspect unfortunately that the answer is "no," but it would be useful to be able to have a unit test for this sort of thing that could make use of a library call or framework rather than needing to write a custom test by hand for each case where it is important.

In case it's not clear what I mean by consistency, for hashCode and equals I refer to the following:

If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.

For equals and compareTo I refer to the following:

The natural ordering for a class C is said to be consistent with equals if and only if e1.compareTo(e2) == 0 has the same boolean value as e1.equals(e2) for every e1 and e2 of class C.

like image 999
Michael McGowan Avatar asked Mar 08 '12 20:03

Michael McGowan


People also ask

Why Compareto () should be consistent to equals () method in Java?

This is because the comparison method of BigDecimal considers only the numeric value, but equals also considers the precision. Since 0.0 and 0.00 have different precisions, they are unequal even though they have the same numeric value.

Why we check hashCode () equality before equals () method?

If an object's hashcode is not the same as another object's hashcode, there is no reason to execute the equals() method: you just know the two objects are not the same. On the other hand, if the hashcode is the same, then you must execute the equals() method to determine whether the values and fields are the same.

Why equals () and hashCode () method used?

The equals() and hashcode() are the two important methods provided by the Object class for comparing objects. Since the Object class is the parent class for all Java objects, hence all objects inherit the default implementation of these two methods.

What is intercommunication between equals method and hashCode method?

If two objects are equal(according to equals() method) then the hashCode() method should return the same integer value for both the objects. But, it is not necessary that the hashCode() method will return the distinct result for the objects that are not equal (according to equals() method).


2 Answers

Guava's tests have a utility called EqualsTester which we use as an everyday part of our unit tests to test equals and hashCode. Its use looks like

new EqualsTester()
  .addEqualityGroup("hello", "h" + "ello")
  .addEqualityGroup("world", "wor" + "ld")
  .addEqualityGroup(2, 1 + 1)
  .testEquals();

which tests that all values in the same group are equal and have the same hash codes, that different groups are not equal, and that various other invariants are all satisfied. You could either use it yourself, or just borrow its ideas.

I would be extremely surprised if it was possible to test without generating or explicitly specifying test values, just because that seems very likely equivalent to the halting problem.

like image 128
Louis Wasserman Avatar answered Sep 28 '22 22:09

Louis Wasserman


If you're using JUnit, the extensions package has the EqualsHashCodeTestCase, which fully tests both equals and hashCode for everything outlined in the Java spec (reflexive, transitive, symmetric, etc). All you have to do is provide an equal and not equal object for the parent class to use for checking.

Since the CompareTo method is part of the Comparable interface, it's actually split out into another test case - the ComparabilityTestCase. This takes three objects - one of lesser value, equal value, and greater value. Override these and the parent class will take care of the rest.

like image 36
josh-cain Avatar answered Sep 28 '22 22:09

josh-cain