Reputation: 1432
The java docs say this:
Throws:
ClassCastException - if the key is of an inappropriate type for this map (optional)
NullPointerException - if the specified key is null and this map does not permit null keys (optional)
I am sure there is a good reason for this decision, but I don't know exactly what it is. Shouldn't containsKey always return false even if the map doesn't allow null values as keys? Null clearly isn't a key in the map if the map doesn't allow keys, so I would think it should return false.
The particular instance I am thinking of is a TreeMap. I changed a Map instance from a HashMap to a TreeMap for performance reasons, and this caused a subtle bug, because containsKey for HashMap does not throw a null pointer exception. I feel like there is not a good reason for this type of change to cause a subtle bug like this.
Edit I am aware of the (optional) nature of the NullPointerException. Its optional nature does not, in my opinion, explain why it is allowed
To give a little more context as to why I am confused about this, containsKey is essentially comparing keys via equality. I am, to some degree, coming from a functional background, wherein (in say, Haskell) the equivalent of containsKey would have an equality constraint on it, and would be valid for all values which can be compared via equality.
The java docs for Object.equals says
For any non-null reference value x, x.equals(null) should return false.
Therefore, I would think that containsKey must return false if the map does not support null keys, since the implementation "should" be equivalent to iterating over the keys with k.equals(input).
Upvotes: 0
Views: 4351
Reputation: 11136
First of all, containsKey(Object key)
is declared in the Map<K, V>
interface, which does not declare throwing anything, therefore, it depends on the implementation.
If the question is why implementations do not do all those (null, cast) checks internally and why do they throw exceptions, I think it is because of design, and for a good reason, to clearly give the output what has gone wrong.
Note, that:
null
, which is also the reason to process this scenario.Note, that both exceptions are defined as optional ones, so, again, it is NOT the must that implementation should be throwing them.
Upvotes: 0
Reputation: 159225
Your argument applies evenly to the ClassCastException
: Shouldn't containsKey
always return false even if the map doesn't allow that type of value as keys?
Answer: Instead of forcing implementations to check the given key for validity, the API (documented behavior) allows an exception to be thrown for invalid key values.
Note that both exceptions are listed as "(optional)", which means that is it up to the implementation whether to do that. The implementation may choose to simply return false
, or it may choose to throw one of those exceptions.
Implementations will probably choose to not add special logic for this, so if the algorithm "natively" throws exception, then so be it. The API was documented to allow this default behavior.
E.g. TreeMap
will natively throw ClassCastException
, because that will happen when trying to call compare()
/ compareTo()
. HashMap
doesn't care about the object type, so will never throw ClassCastException
.
The logic of containsKey()
for a map that doesn't support null keys may or may not do something that throws NullPointerException
if the given key is null, and that is a valid results, so the logic doesn't have to waste extra code to handle it.
Upvotes: 2
Reputation: 190
I believe that this is a design decision that was made.
There are two possible scenarios:
1. You use containsKey on a map that supports a null key. As the user of this function you expect to get either true or false. There's absolutely no reason to get back nullPointerException as we're seeing 'null' as any other key, so like you would expect 'someKey' to return false if it doesn't exist, same for null.
2. You use containsKey on a map that doesn't support a null key. Returning false would be a weird decision because it is not a possible key. Also the user might have a reference to some object which he tries to use as a key. The user would prefer to get a NullPointerException so he would be aware of this situation, trying to get/set a null object as key.
Upvotes: 0