What is the easiest/best way to convert
Map<String, Object>
to
HashMap<String, String>
The API I am using has methods that return a Map but it would be easier if I didn't have to cast the Object to a String each time.
Also, is this even worth doing? Would a HashMap be faster/more efficient than a Map?
I'm assuming I'll have to loop through the original Map and copy the values to the new HashMap.
Thanks in advance!
You can use the constructor as others mentioned:
Map<String, String> newMap = new HashMap(oldMap);
This will only work however if you know that the Object
s in question are really String
s.
but there is something I should mention:
Do not confuse interfaces with classes . Map
is just an interface ; a contract which contains only definitions. A class on the other hand is a concrete implementation of an interface . So it does not make any difference in terms of perfomrance if you use the Map
interface or its runtime type ( HashMap
). It can make a difference however if you swap the implementations (to TreeMap
for example).
Edit:
Here is the verbose solution which is liked by EE guys (no casting/rawtypes warning involved):
public class MapConverter {
public Map<String, String> convert(Map<String, Object> oldMap) {
Map<String, String> ret = new HashMap<String, String>();
for (String key : oldMap.keySet()) {
ret.put(key, oldMap.get(key).toString());
}
return ret;
}
}
Using the copy constructor on raw types works:
HashMap<String, String> hashMap = new HashMap(map);
However, the solution is ugly as the type system is ignored.
EDIT1:
When you execute
public static void main(String[] args) throws IllegalArgumentException,
InterruptedException, IOException {
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("Bla", new Object());
HashMap<String, String> hashMap = new HashMap(map);
System.out.println(hashMap.get("Bla").getClass());
}
you get the class cast exception:
Exception in thread "main" java.lang.ClassCastException: java.lang.Object cannot be cast to java.lang.String
It is thrown when "System.out.println(hashMap.get("Bla").getClass());" is executed.
Consequently, the casts are actually delayed.
EDIT2:
You can avoid the copy with
HashMap<String, String> hashMap = (HashMap)map;
However, the problem remains the same as the following code shows:
public static void main(String[] args) throws IllegalArgumentException,
InterruptedException, IOException {
HashMap<String, Object> oldMap = new HashMap<String, Object>();
oldMap.put("Bla", new Object());
HashMap<String, String> hashMap = (HashMap)oldMap;
System.out.println(hashMap.get("Bla").getClass());
}
It behaves like the other example above in EDIT1.
EDIT3: What about using a lambda?
Map<String, Object> map = new HashMap<String, Object>();
// 1
final Stream<Map.Entry<String, Object>> entries = map.entrySet()
.stream();
final Function<Map.Entry<String, Object>, String> keyMapper = (
Map.Entry<String, Object> entry) -> entry.getKey();
final Function<Map.Entry<String, Object>, String> valueMapper = (
Map.Entry<String, Object> entry) -> {
final Object value = entry.getValue();
if (value instanceof String) {
return (String) value;
} else {
throw new ClassCastException("Value '" + value + "' of key '"
+ entry.getKey() + "' cannot be cast from type "
+ ((value != null) ? value.getClass().getName() : null)
+ " to type " + String.class.getName());
}
};
final BinaryOperator<String> duplicateHandler = (key1, key2) -> {
throw new IllegalStateException(String.format("Duplicate key %s",
key1));
};
final HashMap<String, String> hashMap = entries.collect(Collectors
.toMap(keyMapper, valueMapper, duplicateHandler, HashMap::new));
System.out.println(hashMap);
If map only has string-to-string entries, it will copy them all. Eg Insert
map.put("aKey", "aValue");
at comment 1. It will print
{aKey=aValue}
which is fine.
If you have at least one string-to-non-string entry in your map, copying will fail.
Eg Insert
map.put("aKey", 42);
at comment 1. It will print
Exception in thread "main" java.lang.ClassCastException: Value '42' of key ' aKey' cannot be cast from type java.lang.Integer to type java.lang.String
at ...
which shows the string-to-non-string entry.
I know this solution is not so simple but it is safe.
If you know the types of key and value (like <String, String>
), you can just cast the whole map:
Map<String, String> newMap = (HashMap<String, String>)oldMap;
If you need a separate Map
instance, you can use the constructor of HashMap
like this:
HashMap<String, String> = new HashMap<String, String>((HashMap<String, String>) oldMap);
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.