<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Transient Technology &#187; hashcode</title>
	<atom:link href="http://martinaharris.com/tag/hashcode/feed/" rel="self" type="application/rss+xml" />
	<link>http://martinaharris.com</link>
	<description>Next time you look it might be gone</description>
	<lastBuildDate>Wed, 25 Apr 2012 09:52:12 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>Testing java equals and hashcode methods</title>
		<link>http://martinaharris.com/2009/10/testing-java-equals-and-hashcode-methods-essential/</link>
		<comments>http://martinaharris.com/2009/10/testing-java-equals-and-hashcode-methods-essential/#comments</comments>
		<pubDate>Sat, 24 Oct 2009 21:44:35 +0000</pubDate>
		<dc:creator>Martin Harris</dc:creator>
				<category><![CDATA[java]]></category>
		<category><![CDATA[software quality]]></category>
		<category><![CDATA[testing]]></category>
		<category><![CDATA[equals]]></category>
		<category><![CDATA[hashcode]]></category>
		<category><![CDATA[junit]]></category>
		<category><![CDATA[quality]]></category>

		<guid isPermaLink="false">http://www.koitok.net/?p=27</guid>
		<description><![CDATA[Equals and hashcode bugs can be difficult to track down.  So why not test them?  This blog shows how easy it is to code some tests <a href="http://martinaharris.com/2009/10/testing-java-equals-and-hashcode-methods-essential/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<h3>Write a java test for the equals method!  What is the point in wasting time on that?</h3>
<p>All good java programmers know the equals and hashcode methods are vitally important.  I have seen some unpredictable behavior through bugs in these two methods.</p>
<p>If your about to click away to something more interesting fine, but first read my page with an <a href="http://www.koitok.net/2009/10/ide-generation-of-equals-methods-has-its-moments/">example equals bug</a>.  See if you can spot the problem before I show the solution.</p>
<h4>Writing a test for the equals method</h4>
<p>Writing a test for equals is so easy its tedious.  Which is perhaps why so much code gets written and not tested.  First from the javadoc what are the specifications for a good equals and hashcode implementations?</p>
<p><span id="more-27"></span></p>
<p><strong><cite>Suns javadoc for the equals method</cite></strong></p>
<ul>
<li>It is reflexive: for any non-null reference value x, x.equals(x) should return true.</li>
<li>It is symmetric: for any non-null reference values x and y, x.equals(y) should return true if and only if y.equals(x) returns true.</li>
<li>It is transitive: for any non-null reference values x, y, and z, if x.equals(y) returns true and y.equals(z) returns true, then x.equals(z) should return true.</li>
<li>It is consistent: for any non-null reference values x and y, multiple invocations of x.equals(y) consistently return true or consistently return false, provided no information used in equals comparisons on the objects is modified.</li>
<li>For any non-null reference value x, x.equals(null) should return false.</li>
</ul>
<p><strong><cite>Suns javadoc for the hashcode method</cite></strong></p>
<ul>
<li>Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified. This integer need not remain consistent from one execution of an application to another execution of the same application.</li>
<li>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.</li>
<li>It is not required that if two objects are unequal according to the equals(java.lang.Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results. However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hashtables.</li>
<h4>Simple implementations for equals and hashcode</h4>
<p>These two implementations were built using the generator in netbeans.  Arguably some further optimisation could be done, especially if the class were made fully immutable.  They are fine for the purpose of this blog.</p>
<pre class="brush: java; gutter: false; wrap-lines: false">
public final class SimpleBean {
    private Integer goodInt = 0;

    public SimpleBean(final Integer goodInt) {
        this.goodInt = goodInt;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final SimpleBean other = (SimpleBean) obj;
        if (this.goodInt != other.goodInt
            &amp;&amp; (this.goodInt == null
                                || !this.goodInt.equals(other.goodInt))) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 41 * hash + (this.goodInt != null ? this.goodInt.hashCode() : 0);
        return hash;
    }
}</pre>
<h4>Test class for SimpleBean just showing the equals and hashcode tests</h4>
<pre class="brush: java; gutter: false;wrap-lines: false">
import org.junit.Test;
import static org.junit.Assert.*;

public class TestSimpleBean {

    static final class Fixture {

        static SimpleBean x = new SimpleBean(new Integer(100));
        static SimpleBean y = new SimpleBean(new Integer(100));
        static SimpleBean z = new SimpleBean(new Integer(100));
        static SimpleBean notx = new SimpleBean(new Integer(1));
    }

    @Test
    /**
     * A class is equal to itself.
     */
    public void testEqual_ToSelf() {

        assertTrue("Class equal to itself.", Fixture.x.equals(Fixture.x));
    }

    /**
     * x.equals(WrongType) must return false;
     *
     */
    @Test
    public void testPassIncompatibleType_isFalse() {
        assertFalse("Passing incompatible object to equals should return false", Fixture.x.equals("string"));
    }

    /**
     * x.equals(null) must return false;
     *
     */
    @Test
    public void testNullReference_isFalse() {
        assertFalse("Passing null to equals should return false", Fixture.x.equals(null));
    }

    /**
     * 1. x, x.equals(x) must return true.
     * 2. x and y, x.equals(y) must return true if and only if y.equals(x) returns true.
     */
    @Test
    public void testEquals_isReflexive_isSymmetric() {

        assertTrue("Reflexive test fail x,y", Fixture.x.equals(Fixture.y));
        assertTrue("Symmetric test fail y", Fixture.y.equals(Fixture.x));

    }

    /**
     * 1. x.equals(y) returns true
     * 2. y.equals(z) returns true
     * 3. x.equals(z) must return true
     */
    @Test
    public void testEquals_isTransitive() {

        assertTrue("Transitive test fails x,y", Fixture.x.equals(Fixture.y));
        assertTrue("Transitive test fails y,z", Fixture.y.equals(Fixture.z));
        assertTrue("Transitive test fails x,z", Fixture.x.equals(Fixture.z));
    }

    /**
     * Repeated calls to equals consistently return true or false.
     */
    @Test
    public void testEquals_isConsistent() {

        assertTrue("Consistent test fail x,y", Fixture.x.equals(Fixture.y));
        assertTrue("Consistent test fail x,y", Fixture.x.equals(Fixture.y));
        assertTrue("Consistent test fail x,y", Fixture.x.equals(Fixture.y));
        assertFalse(Fixture.notx.equals(Fixture.x));
        assertFalse(Fixture.notx.equals(Fixture.x));
        assertFalse(Fixture.notx.equals(Fixture.x));

    }

    /**
     * Repeated calls to hashcode should consistently return the same integer.
     */
    @Test
    public void testHashcode_isConsistent() {

        int initial_hashcode = Fixture.x.hashCode();

        assertEquals("Consistent hashcode test fails", initial_hashcode, Fixture.x.hashCode());
        assertEquals("Consistent hashcode test fails", initial_hashcode, Fixture.x.hashCode());
    }

    /**
     * Objects that are equal using the equals method should return the same integer.
     */
    @Test
    public void testHashcode_twoEqualsObjects_produceSameNumber() {

        int xhashcode = Fixture.x.hashCode();
        int yhashcode = Fixture.y.hashCode();

        assertEquals("Equal object, return equal hashcode test fails", xhashcode, yhashcode);
    }

    /**
     * A more optimal implementation of hashcode ensures
     * that if the objects are unequal different integers are produced.
     *
     */
    @Test
    public void testHashcode_twoUnEqualObjects_produceDifferentNumber() {

        int xhashcode = Fixture.x.hashCode();
        int yhashcode = Fixture.notx.hashCode();

        assertTrue("Equal object, return unequal hashcode test fails", !(xhashcode == yhashcode));
    }
}</pre>
<h3>Conclusions</h3>
<p>To me the benefit is clear.  Its very easy to break these two methods.  Converting one of the attribute types can easily break equals and possibly hashcode.  Its essential to have a test in place to prevent the bug going unnoticed.</ul>
<h3>Note on nulls</h3>
<p>In some cases extra tests may be required for null checking on both sides.  For instance in the case where an object relies upon an inner class to provide it a key, and its possible for this key to be null.:</p>
<pre class="brush: java; gutter: false;wrap-lines: false">
   /**
     * x.key = null, y.key = null, must return false.
     */
    @Test
    public void testKeysNull_NotEqual() {

        Thing noKeyAvailableA = new Thing();
        Thing noKeyAvailableB = new Thing ();
        assertFalse(noKeyAvailableA.equals(noKeyAvailableB));
    }

    /**
     * x.key= null, y.key != null, must return false.
     */
    @Test
    public void testKeyNearsideNullFarsideNotNull_NotEqual() {
        Fixture fixture = new Fixture();
        Thing noKeyAvailable = new Thing ();
        assertFalse(noKeyAvailable.equals(fixture.x));
    }

    /**
     * y.key = null, x.key != null, must return false.
     */
    @Test
    public void testKeyFarsideNotNullFarsideNull_NotEqual() {
        Fixture fixture = new Fixture();
        Thing noKeyAvailable = new Thing ();
        assertFalse(fixture.x.equals(noKeyAvailable));
    }
</pre>
<div class="lightsocial_container"><a class="lightsocial_a" href="http://digg.com/submit?url=http%3A%2F%2Fmartinaharris.com%2F2009%2F10%2Ftesting-java-equals-and-hashcode-methods-essential%2F&amp;title=Testing+java+equals+and+hashcode+methods" target="_blank"><img class="lightsocial_img" src="http://martinaharris.com/wp-content/plugins/light-social/digg.png" alt="Digg This" title="Digg This" /></a>&nbsp;&nbsp;<a class="lightsocial_a" href="http://www.reddit.com/submit?url=http%3A%2F%2Fmartinaharris.com%2F2009%2F10%2Ftesting-java-equals-and-hashcode-methods-essential%2F&amp;title=Testing+java+equals+and+hashcode+methods" target="_blank"><img class="lightsocial_img" src="http://martinaharris.com/wp-content/plugins/light-social/reddit.png" alt="Reddit This" title="Reddit This" /></a>&nbsp;&nbsp;<a class="lightsocial_a" href="http://www.stumbleupon.com/submit?url=http%3A%2F%2Fmartinaharris.com%2F2009%2F10%2Ftesting-java-equals-and-hashcode-methods-essential%2F&amp;title=Testing+java+equals+and+hashcode+methods" target="_blank"><img class="lightsocial_img" src="http://martinaharris.com/wp-content/plugins/light-social/stumbleupon.png" alt="Stumble Now!" title="Stumble Now!" /></a>&nbsp;&nbsp;<a class="lightsocial_a" href="http://buzz.yahoo.com/buzz?targetUrl=http%3A%2F%2Fmartinaharris.com%2F2009%2F10%2Ftesting-java-equals-and-hashcode-methods-essential%2F&amp;headline=Testing+java+equals+and+hashcode+methods" target="_blank"><img class="lightsocial_img" src="http://martinaharris.com/wp-content/plugins/light-social/yahoo_buzz.png" alt="Buzz This" title="Buzz This" /></a>&nbsp;&nbsp;<a class="lightsocial_a" href="http://www.dzone.com/links/add.html?title=Testing+java+equals+and+hashcode+methods&amp;url=http%3A%2F%2Fmartinaharris.com%2F2009%2F10%2Ftesting-java-equals-and-hashcode-methods-essential%2F" target="_blank"><img class="lightsocial_img" src="http://martinaharris.com/wp-content/plugins/light-social/dzone.png" alt="Vote on DZone" title="Vote on DZone" /></a>&nbsp;&nbsp;<a class="lightsocial_a" href="http://www.facebook.com/sharer.php?t=Testing+java+equals+and+hashcode+methods&amp;u=http%3A%2F%2Fmartinaharris.com%2F2009%2F10%2Ftesting-java-equals-and-hashcode-methods-essential%2F" target="_blank"><img class="lightsocial_img" src="http://martinaharris.com/wp-content/plugins/light-social/facebook.png" alt="Share on Facebook" title="Share on Facebook" /></a>&nbsp;&nbsp;<a class="lightsocial_a" href="http://delicious.com/save?title=Testing+java+equals+and+hashcode+methods&amp;url=http%3A%2F%2Fmartinaharris.com%2F2009%2F10%2Ftesting-java-equals-and-hashcode-methods-essential%2F" target="_blank"><img class="lightsocial_img" src="http://martinaharris.com/wp-content/plugins/light-social/delicious.png" alt="Bookmark this on Delicious" title="Bookmark this on Delicious" /></a>&nbsp;&nbsp;<a class="lightsocial_a" href="http://www.dotnetkicks.com/kick/?title=Testing+java+equals+and+hashcode+methods&amp;url=http%3A%2F%2Fmartinaharris.com%2F2009%2F10%2Ftesting-java-equals-and-hashcode-methods-essential%2F" target="_blank"><img class="lightsocial_img" src="http://martinaharris.com/wp-content/plugins/light-social/dotnetkicks.png" alt="Kick It on DotNetKicks.com" title="Kick It on DotNetKicks.com" /></a>&nbsp;&nbsp;<a class="lightsocial_a" href="http://dotnetshoutout.com/Submit?title=Testing+java+equals+and+hashcode+methods&amp;url=http%3A%2F%2Fmartinaharris.com%2F2009%2F10%2Ftesting-java-equals-and-hashcode-methods-essential%2F" target="_blank"><img class="lightsocial_img" src="http://martinaharris.com/wp-content/plugins/light-social/dotnetshoutout.png" alt="Shout it" title="Shout it" /></a>&nbsp;&nbsp;<a class="lightsocial_a" href="http://www.linkedin.com/shareArticle?mini=true&amp;url=http%3A%2F%2Fmartinaharris.com%2F2009%2F10%2Ftesting-java-equals-and-hashcode-methods-essential%2F&amp;title=Testing+java+equals+and+hashcode+methods&amp;summary=&amp;source=" target="_blank"><img class="lightsocial_img" src="http://martinaharris.com/wp-content/plugins/light-social/linkedin.png" alt="Share on LinkedIn" title="Share on LinkedIn" /></a>&nbsp;&nbsp;<a class="lightsocial_a" href="http://www.technorati.com/faves?add=http%3A%2F%2Fmartinaharris.com%2F2009%2F10%2Ftesting-java-equals-and-hashcode-methods-essential%2F" target="_blank"><img class="lightsocial_img" src="http://martinaharris.com/wp-content/plugins/light-social/technorati.png" alt="Bookmark this on Technorati" title="Bookmark this on Technorati" /></a>&nbsp;&nbsp;<a class="lightsocial_a" href="http://twitter.com/home?status=Reading+http%3A%2F%2Fmartinaharris.com%2F2009%2F10%2Ftesting-java-equals-and-hashcode-methods-essential%2F" target="_blank"><img class="lightsocial_img" src="http://martinaharris.com/wp-content/plugins/light-social/twitter.png" alt="Post on Twitter" title="Post on Twitter" /></a>&nbsp;&nbsp;<a class="lightsocial_a" href="http://www.google.com/buzz/post?url=http%3A%2F%2Fmartinaharris.com%2F2009%2F10%2Ftesting-java-equals-and-hashcode-methods-essential%2F" target="_blank"><img class="lightsocial_img" src="http://martinaharris.com/wp-content/plugins/light-social/google_buzz.png" alt="Google Buzz (aka. Google Reader)" title="Google Buzz (aka. Google Reader)" /></a>&nbsp;&nbsp;</div><div class="dzone_button" style="float: right; margin-left: 5px;">
<script type="text/javascript">
var dzone_url = 'http://martinaharris.com/2009/10/testing-java-equals-and-hashcode-methods-essential/';
var dzone_title = 'Testing java equals and hashcode methods';
var dzone_blurb = '';
var dzone_style = '2';
</script>
<script language="javascript" src="http://widgets.dzone.com/links/widgets/zoneit.js"></script>
</div>]]></content:encoded>
			<wfw:commentRss>http://martinaharris.com/2009/10/testing-java-equals-and-hashcode-methods-essential/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

