Easily convert Map<String, Object> to Map<String, String>
Solution 1
Well you can't safely cast it to a Map<String, String>
because even though you know you've only got strings as the values, the compiler doesn't. That's like expecting:
Object x = "foo";
String y = x;
to work - it doesn't; you need to explicitly cast.
Likewise you can explicitly cast here, too, if you go via Object
:
Map<String, Object> x = ...;
Map<String, String> y = (Map<String, String>) (Object) x;
Now you'll get a warning saying that it's an unchecked cast, because unlike the earlier "object to string" cast, there's no execution-time check that it's really valid. Type erasure means that a map doesn't really know its key/value types. So you end up with checking only being done when elements are fetched:
import java.util.*;
class Test {
public static void main(String[] args) {
Map<String, Object> x = new HashMap<>();
x.put("foo", "bar");
x.put("number", 0);
Map<String, String> y = (Map<String, String>) (Object) x;
// This is fine
System.out.println(y.get("foo"));
// This goes bang! It's trying to cast an Integer to a String
System.out.println(y.get("number"));
}
}
So if you really want to avoid creating a new map, this "cast via Object
" will work - but it's far from ideal.
Your approach is safer, although you can make it slightly more efficient by avoiding the lookup:
public static Map<String, String> copyToStringValueMap(
Map<String, Object> input) {
Map<String, String> ret = new HashMap<>();
for (Map.Entry<String, Object> entry : input.entrySet()) {
ret.put(entry.getKey(), (String) entry.getValue());
}
return ret;
}
Solution 2
A Java 8 solution:
private Map<String, String> stringifyValues(Map<String, Object> variables) {
return variables.entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey, e -> (String) e.getValue()));
}
Solution 3
Good solutions here, but I want to add another one that taking into consideration handling null
values:
Map<String,Object> map = new HashMap<>();
Map<String,String> stringifiedMap = map.entrySet().stream()
.filter(m -> m.getKey() != null && m.getValue() !=null)
.collect(Collectors.toMap(Map.Entry::getKey, e -> (String)e.getValue()));
jobukkit
Updated on July 24, 2022Comments
-
jobukkit almost 2 years
An API I am using has a method that returns a
Map<String, Object>
, but I know theObject
's areString
's in this case, so I want it as aMap<String, String>
.But for some reason I can't just cast it, Java says
Map<String, Object>
cannot be casted toMap<String, String>
, for some reason.I used:
Map<String, Object> tempMap = someApiMethodReturningAMap(); Map<String, String> map = new HashMap<String, String>(); for (String i : tempMap.keySet()) { map.put(i, String.valueOf(tempMap.get(i))); }
as a workaround, but is there an easier way?