A Final Note on hashCode


A Final Note on hashCode

If you code an equals method for a class, also code a hashCode method.


In the absence of hashCode, the compiler won't complain, and you may not encounter any problems. However, unexpected behavior will likely result if you put objects of that class into a hash table based collection (the class java.util.Set also uses a hash table implementation). Figuring out that there is a missing hashCode method can waste a considerable amount of time. Get in the habit of coding hashCode if you code equals!

If performance is a consideration, you may want to write unit tests for the hash code. One technique is to load a HashSet with a large number of elements, testing the performance to ensure that the insertions execute in a reasonable time. If not, the hash table probably managed a high number of collisions.

 public void testHashCodePerformance() {    final int count = 10000;    long start = System.currentTimeMillis();    Map<Course, String> map = new HashMap<Course, String>();    for (int i = 0; i < count; i++) {       Course course = new Course("C" + i, "" + i);       map.put(course, "");    }    long stop = System.currentTimeMillis();    long elapsed = stop - start;    final long arbitraryThreshold = 200;    assertTrue("elapsed time = " + elapsed,       elapsed < arbitraryThreshold); } 

There are many ways to test performance, but the above test provides a simple, adequate mechanism. The class java.lang.System contains a static method, currentTimeMillis, that returns the milliseconds representing the current time stamp. Before starting, you store the current timestamp in a local variable (start). You execute the desired code n times using a for loop. When the loop completes, you capture the timestamp (stop). You obtain the elapsed time by subtracting the start time from the stop time. The assertion ensures that the loop completed in a reasonable amount of time (arbitraryThreshold).

The assertTrue method call contains a String as its first parameter. The String gets printed by JUnit as part of the error message only if the assertion fails. In this example, the failure will show how long the loop actually took to execute.

You may want to isolate performance tests in a separate suite. You will still want to run them regularly (perhaps daily, or after you have completed a significant task). The nature of performance tests makes them slow, however, so you may not want the constant negative impact to the performance of your functional unit test suite.

If you find you need more comprehensive unit testing, either build your own framework by eliminating duplication or consider a tool such as JunitPerf.[9] JUnit itself contains some rudimentary hooks to help you with repetitive testing.

[9] See http://www.clarkware.com/software/JUnitPerf.html.

To demonstrate the usefulness of the example performance test, change the hashCode implementation in Course to return a constant number:

 @Override public int hashCode() {    return 1; } 

Even with only 10,000 entries into the HashMap, the test should fail miserably. Revert the hashCode to its previous form; the test should now pass.

Another technique for testing hashCode is to ensure that the variance that a number of hash codes produces is reasonably high. The variance is a measure of how spread out a distribution of numbers is. You calculate the variance as the average of the squared deviation of each number from the mean.

The problem with both of these testing techniques is that they are based on arbitrary measures of what is acceptable. As a developer, you can determine the value of this kind of testing and choose to defer it until you can pinpoint a true performance problem to the hash table.

Minimally, you should at least write enough tests to prove that the contract for hashCode holds true.



Agile Java. Crafting Code with Test-Driven Development
Agile Javaв„ў: Crafting Code with Test-Driven Development
ISBN: 0131482394
EAN: 2147483647
Year: 2003
Pages: 391
Authors: Jeff Langr

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net