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...
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
.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With