Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are exceptions in hashCode and equals methods allowed and acceptable in Java?

Some classes filled by frameworks (like beans). So you can't guaranty that all fields set.

Look to example: classes marked as @Entity usually have Integer id field. hashCode can be written as:

public int hashCode() {
    return id.hashCode();
}

but defensive code may look like:

public int hashCode() {
    return (id != null) ? id.hashCode() : 0;
}

Do I need write checks for null or surround code with try { ... } catch (Exception e) in hashCode and equals functions?

I have no arguments for defencive coding is such case because it hide putting inconsistent objects to collections and lead to late errors. Am I wrong in this position?

UPDATE I wrote such code:

import java.util.*;

class ExceptionInHashcode {

    String name;

    ExceptionInHashcode() { }
    ExceptionInHashcode(String name) { this.name = name; }

    public int hashCode() {
        // throw new IllegalStateException("xxx");
        return this.name.hashCode();
    }

    public static void main(String args[]) {
        Hashtable list = new Hashtable();
        list.put(new ExceptionInHashcode("ok"), 1);
        list.put(new ExceptionInHashcode(), 2); // fail
        System.out.println("list.size(): " + list.size());
    }
}

and run it:

java -classpath . ExceptionInHashcode
Exception in thread "main" java.lang.NullPointerException
        at ExceptionInHashcode.hashCode(ExceptionInHashcode.java:12)
        at java.util.Hashtable.hash(Hashtable.java:262)
        at java.util.Hashtable.put(Hashtable.java:547)
        at ExceptionInHashcode.main(ExceptionInHashcode.java:18)

I think that I can find error early instead of returning zero if object is in wrong state...

like image 706
gavenkoa Avatar asked Mar 01 '13 06:03

gavenkoa


3 Answers

In general, the answer is "it depends".

  • If you should never see instances of the class with null for that field, then it is reasonable to allow an NPE to be thrown. The NPE indicates a bug; i.e. a situation where your informal invariant is broken.

  • If there are circumstances where an instance with a null could reasonably expected, then you should deal with the null case without throwing an exception.


In this particular case, you are apparently dealing with objects where the id field can be null if the object hasn't been persisted yet. This presents a tricky problem:

  • If you don't allow null for the id, then you have to be careful not to put non-persistent objects into a hash table.

  • If you do allow null for the id, then you have the problem that if you add an object to a hash table and THEN persist it, the hashcode may change leading to breakage of the hash table. So, now you need to defend against THAT ... by memoising the object's hashcode value in a transient field. And roughly the same problem occurs with equals. If equality changes when an object is persisted, then you had better not mix persisted and non-persisted keys in the same hash table.

Taking all of that into account, I'd advise to either throw that NPE, or not use the id fields in equals / hashcode.

like image 188
Stephen C Avatar answered Oct 20 '22 21:10

Stephen C


I would personally check for nullity and make the methods always return with no exceptions.

While runtime exceptions often aren't documented and can be thrown anywhere, I think it would be generally poor for them to be thrown by equals and hashCode. On the one hand, I can definitely see your point about being put in maps before being fully populated... but on the other hand it's hard to really know where equals will be called.

As lc says in comments, if you really want to throw an exception, it would be much better to throw an IllegalStateException to make it crystal clear that this was deliberate, than to let a NullReferenceException be thrown "by default" which makes it look like you just didn't think about the null scenario.

like image 22
Jon Skeet Avatar answered Oct 20 '22 21:10

Jon Skeet


For validating the state of the object you should use Bean validation framework to make sure the state of the object is valid.

No hashcode and equals method should not throw Exceptions.

equals method must have checks for nullity. And when the object is created it is creators responsibility to make sure that the object is in valid state, so hashCode would never have to throw an exception. For that bean validation can be used. IMO.

UPDATE: As you are using bean frameworks which create beans for you, you have to rely on bean validation. But otherwise it MUST be the responsibility of the Factory that creates the object to make sure that only a valid instance is created.

like image 2
Narendra Pathai Avatar answered Oct 20 '22 20:10

Narendra Pathai