Reputation: 4695
Consider the specification for the put
method of the java.util.Map
interface.
It says:
@throws ClassCastException if the class of the specified key or value
prevents it from being stored in this map
Map
is a generic interface with two type parameters: K
and V
for key objects and value objects respectively. The put
method signature is:
V put(K key, V value);
Under what conditions might a call to this method cause a ClassCastException
at runtime?
I reckon that if there is some mixing of generic and raw types, then while ignoring the compiler warnings this may happen. So, after rereading Effective Java 2, I modeled the following after the unsafeAdd
example (Item #23, pp. 112):
public class MapClassCastException {
public static void main(String[] args) {
Map<Integer, String> m = new HashMap<>();
unsafePut(m);
System.out.println(m.get(1));
}
private static void unsafePut(Map m) { // beware: Raw Type
m.put("blow", "up");
m.put(new int[]{2, 4}, "xxx");
}
}
But this code does not fail at runtime with ClassCastException
, instead it prints null
. (Of course, I am ignoring the compiler warnings only to understand it well).
Can someone demonstrate how Map#put
might throw a ClassCastException
at runtime? (I tried this with JDK 1.6, 1.7 and 1.8 and they produced identical results).
Upvotes: 3
Views: 1035
Reputation: 22435
Map
is an interface, which essentially defines a contract for all implementations of that interface. The documentation for Map.put
is telling you that it's possible for this method to throw a ClassCastException
. That doesn't require all implementations to throw it.
If you look at the documentation for HashMap.put
, you'll notice that it doesn't mention ClassCastException
at all. As mentioned in the comments, TreeMap.put
does throw a ClassCastException
because it needs to be able to accurately compare the keys.
If you wanted to implement your own java.util.Map
, you could then throw ClassCastException
if you wanted to restrict the type of a key or value, even though the generics on the interface cannot enforce that if you happen to be using a raw Map
type.
I think this is just the implementors of the Collections API saying to be careful.
Upvotes: 2