1

I have class with final String as unique ID. Of course I want to override equals so comparison is based on ID only. Is it correct practice then to just return hash code of ID, like below?

class ItemSpec{
    final String name;

    ...

    @Override
    public boolean equals(Object o){
        if(o != null && o instanceof ItemSpec){
            return name.equalsIgnoreCase(((ItemSpec)o).name);
        } else{
            return false;
        }
    }

    @Override
    public int hashCode(){
         if(name == null){
             return 0;
         } else{
             return name.hashCode();
         }
    }
}
Luiggi Mendoza
  • 85,076
  • 16
  • 154
  • 332

2 Answers2

12

Not if your equals is case insensitive. You could have two ItemSpec coming out as equal but with different hash codes. That breaks the most crucial requirement of a hash code.

Your equals has to agree with your hashCode. So if you are going to compare them case insensitively, you have to write your hashCode case insensitively.

@Override
public int hashCode(){
     if (name == null){
         return 0;
     } else{
         return name.toLowerCase().hashCode();
     }
}

Also your hashCode method implies that name could be null. If so, you should null-check it in your equals method as well.

khelwood
  • 55,782
  • 14
  • 81
  • 108
  • 2
    Can't there be a case where `a.equalsIgnoreCase(b)` but `a.toLowerCase().equals(b.toLowerCase())` is false? – assylias Sep 19 '14 at 15:09
  • 1
    Good catch, but wanted to point out the same as assylias: The conversion may open the door for a locale-specific and unicode-related hassle... – Marco13 Sep 19 '14 at 15:10
  • Well I realised that myself and edited, but you sir are just too fast for me ;) – NoMercyIncluded Sep 19 '14 at 15:14
  • 1
    If there is a case where `equalsIgnoreCase` is coarser than `toLowerCase`, then I guess the best way to be certain they match up is to use `a.toLowerCase().equals(b.toLowerCase())` in the `equals` method. – khelwood Sep 19 '14 at 15:20
-1

I dont see any problem with your approach.

But, I've often seen the following implementation:

public int hashCode() {
    final int prime = 31;
    int result = super.hashCode();
    result = prime * result + ((name == null) ? 0 : name.hashCode());
    return result;
}

Update: Here is a link with a better explanation: Best implementation for hashCode method

Community
  • 1
  • 1
Jama Djafarov
  • 358
  • 3
  • 11
  • That looks like auto-generated code and does not do much apart from increasing the computation time... – assylias Sep 19 '14 at 15:12
  • 5
    You can't incorporate `super.hashCode` into your hashcode if you're not requiring `super.equals` in your equals method. Otherwise two equal objects may get different hashcodes. – khelwood Sep 19 '14 at 15:13
  • I took this code from my project. I am not 100% certain, if I did it manually, or it was Eclipse generated. But I did look at the most common approach to implement hashCode, and this was most common approach in my view. – Jama Djafarov Sep 19 '14 at 15:25
  • It was popularised in Joshua Bloch's book, 'Effective Java'. There are variants of it, and quite a lot of the JDK libraries use it. For example Arrays.hashCode. It is done to spread out the hashCodes over the limited range, and to try to reduce pooling/hotspots within the hashed range. Which all affect the performance of hashmaps and the like. – Chris K Sep 19 '14 at 15:41