How can I cast a Map<Object,Object>
to Map<String,String>
in the cleanest way?
Is there a way to do that without ite开发者_如何转开发rating over the map?
Thanks
The actual answer is:
Map<Object,Object> valueMap = ...;
@SuppressWarnings("unchecked")
Map<String,String> targetMap = (Map)valueMap;
I think it's a good idea to explain why the simple solution doesn't work and why you never, ever should use this.
Assume you could cast List<Object>
to List<String>
(the same applies to Map, just a simpler interface). What would you expect to happen from the following code:
List<Object> m = Something;
m.add("Looks good.");
m.add(42);
List<String> s = (List<String>)m; // uhuh, no we don't want that.
String myString = s.get(1); // huh exception here.
Now you CAN hack it indeed using Bohemians/Chris solution, but you basically destroy Java's type system. DON'T DO THAT. You don't want a List<String>
to contain an Integer! Have fun debugging that later on - the additional code of looping through all variables will avoid lots of headaches and hardly is a performance problem.
If there's a reason to declare the Map as taking an Object instead of a String someone may add any object to it - usually you should be able to avoid this with a better generic.
If you want something clean, you must convert "deeply"! keys and values.
Using Java 8 stream, this take only a few lines:
static public Map<String, String> toStringString(Map<? extends Object, ? extends Object> map) {
return map
.entrySet()
.stream()
.collect(Collectors.toMap(
e -> e.getKey().toString(),
e -> e.getValue().toString()
));
}
public Map<String, String> castOnlyStringValues(final Map<String, Object> map) {
return map.entrySet().stream()
.filter(x -> String.class.isAssignableFrom(x.getValue().getClass()))
.map(x -> (Entry<?, ?>) x).map(x -> (Entry<String, String>) x)
.collect(toMap(Entry::getKey, Entry::getValue));
}
Building on Chris J's answer, here's his "hack" code in action, showing it works:
public static void main(String[] args) {
Map<Object, Object> valueMap = new HashMap<Object, Object>();
valueMap.put("foo", "bar");
@SuppressWarnings("unchecked")
Map<String, String> targetMap = (Map<String, String>) ((Object) valueMap); // hack alert!
for (Map.Entry<String, String> entry : targetMap.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
System.out.println(key + "=" + value); // prints foo=bar :)
}
}
Wow! No runtime exceptions :)
精彩评论