Chapter 7 - page 585
On top of page 585 two implementations for a hashCode() method are proposed referring to the previous example starting on page 583.
Following questions about these methods are asked on top of page 585:
Time for another pop quiz: Are the preceding two hashCodes legal? Will they successfully retrieve objects from a Map? Which will be faster?
Answer is given on top of page 585 as
The answer to the first two questions is Yes and Yes.
Correct answer should however be:
The answer to the first question is No for the first proposed method and Yes for the second proposed method. (I happily omit the answer to the second question).
Problem is the possible NullPointerException. Important to mention as NPE's are source of many (also serious) errors. The possible NPE is mentioned in several discussions. However I did not find a statement that because of this NPE the proposed method fails to fulfill contract for hashCode().
Code referred to on page 583 is as below (I assume this code is referred as otherwise the examples lack context):
The hashCode() Contract from the Java API is on page 554. The second condition is as below:
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.
To "produce the same integer result" in this sense implicitly assumes that the hashCode() method for both objects completes in the case "If two objects are equal according to the equals(Object) method". So in more detail the above can be stated that "If two objects are equal according to the equals(Object) method" the hashCode() method for both objects must complete and the obtained integer result for both methods must be the same.
The code below shows an example where two dog objects are equal but the hashCode() method on any of the objects does not complete. So the contract of the hashCode() method is not fulfilled.
Code sample:
The code above gives the following output:
true
HashCode comparison not possible
In line 21 there is no problem. The two objects dog1 and dog2 are equal regarding the equals(Object) method. There is no problem here. dog2 is an instance of Dog and dog2.name is null as the name field of dog1. So the equals(Object) method yields true.
In line 23 however there is of course a problem. When invoking the hashCode() method to compare the hashCodes on any of the two objects a NullPointerException occurs. The length() method is invoked on the name field which contains a null value for both objects.
So comparison of the hashCodes is not possible as at least one hashCode() method does not complete (in fact both) - so the contract of the hashCode() method is not fulfilled.
The problem here is really that the hashCode() contract requires the hashCod() method to complete on both involved objects if the objects are equal as stated above. It does not say that when one of the methods does not complete the contract is fulfilled – in the contrary in this very case the contract is not fulfilled.
Of course it is easy to add a null check to the proposed method so that the hashCode() contract is fulfilled. I will however not to do so as it only distracts from the actual design (which is that you can have dogs with no names ...).