I am writing a recursive converter for a Map<String, Object>
(meaning the Object
part can also be a Map<String, Object>
, and so on...
The code snippet:
if(value instanceof Map) {
try {
return convert((Map<String, Object>)value);
} catch (ClassCastException ccex) {
ccex.printStackTrace();
return null;
}
}
still has a warning on (Map<String, Object>)value
:
Type safety: Unchecked cast from Object to Map<String,Object>
While I can annotate it with @SuppressWarnings("unchecked")
, what I am curious about:
Is the catch (ClassCastException ccex)
block above enough to avoid any issues with that unsafe cast?
Is the
catch (ClassCastException ccex)
block above enough to avoid any issues with that unsafe cast?
No, precisely because it's not checked. It will check that it's a Map
, but that's all it is at the JVM level, due to type erasure. It could contain non-String keys, and that cast won't detect it.
Consider this example:
import java.util.*;
class Test {
public static void main(String[] args) throws Exception {
Map raw = new HashMap();
raw.put(new Object(), 10);
// This cast won't fail
Map<String, Object> typed = (Map<String, Object>) raw;
// But this will fail...
for (String key : typed.keySet()) {
System.out.println(key);
}
}
}
Basically the compiler is inserting a cast on each access to keys or values, and those hidden casts can fail - but they're not at the same place as the cast to Map<String, Object>
.
See more on this question at Stackoverflow