Kedar Mhaswade
Kedar Mhaswade

Reputation: 4695

Why does Map#put specify @throws ClassCastException?

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

Answers (1)

Jeremy
Jeremy

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

Related Questions