Given the following situation:
Map<String, Object> map1 = new HashMap();
Map<String, String> map2 = new HashMap();
map2.put("Grp A", "a");
map2.put("Grp B", "b");
map1.put("Grp",map2);
How can get the "Grp A" value from map1 ?
Change map1 to:
Map<String, Map<String, String>> map1 = new HashMap<>();
Then map1.get("Grp").get("Grp A") will work.
Of course, in general it would be safer to store map1.get("Grp") in a variable, and check if it's not null before calling the second get():
String value = null;
Map<String, String> inner = map1.get("Grp");
if (inner != null) {
value = inner.get("Grp A");
}
If you must keep map1 as Map<String, Object> (for example, if you must store values of different types in it), you'll have to check the type of the value you got from the outer Map, and cast it to a Map before obtaining the inner value:
String value = null;
Object innerObj = map1.get("Grp");
if (innerObj instanceof Map<?,?>) {
Map<?,?> inner = (Map<?,?>) map1.get("Grp");
Object obj = inner.get("Grp A");
if (obj instanceof String) {
value = (String) obj;
}
}
Simply retrieve map2 from map1 by casting to a Map and then get the desired value from that Map:
return ((Map<String,String>)map1.get("Grp")).get("Grp A");
However, better practice would be to check that map2 isn't null before retrieving "Grp A":
Map<String,String> map = (Map<String,String>)map1.get("Grp");
if (map != null) {
return map.get("Grp A");
}
#Eran's answer would be better practice, but OP asked how to retrieve the value from the given HashMap.
Since you defined map1 as Map<String, Object> it's values are returned as objects.
You can solve this by either by .
Casting .
Map<String,String> map2 = = (Map<String,String>)map1.get("Gep")
Using the right generics for m1 .
Map<String, Map<String, String>> map1 = new HashMap<>();
Below is the solution for the above problem
import java.util.HashMap;
import java.util.Map;
public class HashMapExample {
public static void main(String[] args) {
Map<String, String> map2 = new HashMap<>();
Map<String, Map<String, String>> map1 = new HashMap<>();
map2.put("Grp A", "a");
map2.put("Grp B", "b");
map1.put("Grp",map2);
System.out.println(map1.get("Grp").get("Grp A"));
}
}
Hope this will work
Thanks...
Related
I have Hashmap of <String, Object> that could contain different object type like String, Int. So I have already successfully cast the object to int and string. But When I try to cast it into a hashmap that doesn't work and I have empty value with no error.
Here is what I have try :
String str = "hey";
Int intVal= 66;
HashMap<String, String> myGetHashMapVal= new HashMap<>();
HashMap<String,Obj> objHashMap = new HashMap<>();
objHashMap.put("TheString",str);
objHashMap.put("TheInt",intVal);
objHashMap.put("HashMap",myGetHashMapVal);
HashMap<String, Object> hashMap = (HashMap<String, Object>) objHashMap.get("HashMap");
Well, this works just fine for me.
HashMap<String,Object> map = new HashMap<>();
map.put("myMap", map);
map.put("int", 1);
#SuppressWarnings("unchecked")
HashMap<String,Object> map2 = (HashMap<String,Object>)map.get("myMap");
System.out.println(map2.get("int"));
Prints
1
This question already has answers here:
Reverse HashMap keys and values in Java
(12 answers)
Closed 5 years ago.
I have a Map(map1) whose key is another map(map2) and value is string.
The value of map1 has several duplicate, so I must group them and set as key in another map3 whose value has to be map2.
eg:
map1 { [[a,b],xyz], [[c,d],wrt] , [[e,f],xyz] , [[r,m],xyz] }
output should be :
map3 { [ xyz,[ [a,b],[e,f],[r,m] ] ] , [ wrt,[ [c,d] ]
can i obtain like this ?
try MultiValueMap from (commons-collections) library
Map map1 = new HashMap<String[], String>();
map1.put(new String[]{"a", "b"}, "xyz");
map1.put(new String[]{"c", "d"}, "wrt");
map1.put(new String[]{"e", "f"}, "xyz");
map1.put(new String[]{"c", "d"}, "xyz");
MultiValueMap map2 = new MultiValueMap();
for(String[] key: map1.keySet()) {
String value = map1.get(key);
map2.add(value, key);
}
// now you got map2 as you want
NO, Though you can declare it but while using it, it may allow same keys(human readable). Because Map do not override Object's equals method your key comparison will be on JVM's object level (it may be different for objects with same values in them).
You can use the stream API to solve it:
Map<String, List<Map<String, String>>> map3 = map.entrySet().stream()
.collect(Collectors.groupingBy(Entry::getValue,
Collectors.mapping(Entry::getKey,
Collectors.toList())));
Explanation:
The entries will be grouped by its values (groupingBy(Entry::getValue).
But the values should not be a list of entries so the downstream is necessary. This is the list of keys of the original map.
It is not clear from your post what do you mean by map2, but let's assume you would like to use each Map.Entry<String, String> entry from map2 for each key for map1.
The following code is Java 7, it's a bit verbose. It could be done shorter with Java 8 streams, I guess.
public class MapReverser {
private Map<Map.Entry<String, String>, String> map1 = new HashMap<>();
private Map<String, String> map2 = new LinkedHashMap<>();
private void prepareMaps() {
map2.put("a", "b");
map2.put("c", "d");
map2.put("e", "f");
map2.put("r", "m");
String[] valueArray = { "xyz", "wrt", "xyz", "xyz" };
int i = 0;
for (Map.Entry<String, String> entry : map2.entrySet()) {
map1.put(entry, valueArray[i]);
i++;
}
}
public Map<String, List<Map.Entry<String, String>>> reverse() {
Map<String, List<Map.Entry<String, String>>> reversedMap = new HashMap<>();
for (Map.Entry<Map.Entry<String, String>, String> entry : map1.entrySet()) {
List<Map.Entry<String, String>> reversedMapValue = reversedMap.get(entry.getValue());
if (reversedMapValue == null) {
reversedMapValue = new ArrayList<>();
}
reversedMapValue.add(entry.getKey());
reversedMap.put(entry.getValue(), reversedMapValue);
}
return reversedMap;
}
private void printResult(Map<String, List<Map.Entry<String, String>>> reversedMap) {
for (Map.Entry<String, List<Map.Entry<String, String>>> entry : reversedMap.entrySet()) {
System.out.println("Key: \n" + entry.getKey());
System.out.println("Values:");
List<Map.Entry<String, String>> valuesList = entry.getValue();
for (Map.Entry<String, String> value : valuesList) {
System.out.println(value );
}
System.out.println("\n");
}
}
public static void main(String[] args) {
MapReverser mapReverser = new MapReverser();
mapReverser.prepareMaps();
Map<String, List<Map.Entry<String, String>>> reversedMap = mapReverser.reverse();
mapReverser.printResult(reversedMap);
}
}
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 Objects in question are really Strings.
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.
E.g. 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.
E.g. 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);
How do I put values in this map?
public static Map<String, TreeMap<String, SomeClass>> myMap=Collections.synchronizedMap(new TreeMap<String, TreeMap<String,SomeClass>>());
First you need to make sure the "inner map" exists, then you can put values into it:
String outerKey = "exampleKey1";
String innerKey = "exampleKey2";
SomeClass innerValue = new SomeClass();
TreeMap<String, SomeClass> innerMap = myMap.get(outerKey);
if (innerMap == null) {
innerMap = Collections.synchronizedMap(new TreeMap<String, SomeClass>());
myMap.put(outerKey, innerMap);
}
innerMap.put(innerKey, innerValue);
You should also consider changing the type to:
public static Map<String, SortedMap<String, SomeClass>> myMap = ...
// ^^^^^^^^^
or just Map depending on if you need the sorted property.
TreeMap<String, SomeClass> map = myMap.get(key1)
if(map == null) {
map = Collections.synchronizedMap(new TreeMap<String, SomeClass>());
myMap.put(key1, map);
}
map.put(key2, value);
TreeMap<String, SomeClass> value = new TreeMap<String, SomeClass>();
myMap.put("key", value);
I have a method in a class, which initialize a HashMap and put some keys and values inside it, then the method returns the HashMap. How can I retrieve the returned HashMap?
public Map<String, String> getSensorValue(String sensorName) {
registerSensor(sensorName);
sensorValues.put("x","25");
sensorValues.put("y","26");
sensorValues.put("z","27");
return sensorValues;
}
And here I call this method from another class:
public static HashMap<String, String> sensValues = new HashMap<String, String>();
AllSensors sensVal = new AllSensors();
sensValues.putAll(sensVal.getSensorValue("orientation"));
String something = sensValues.get("x");
But it does not work in this way
sensValues.putAll(sensVal.getSensorValue("orientation"));
Makes my android application crash.
The point is to retrive returned HashMap somehow.
You shouldn't have to copy the map. Just try using the returned reference:
Map<String, String> map = sensVal.getSensorValue("...");
Your method needs to return a Map<String,String>. In the code you have posted, the Map sensorValues is never initialized.
public Map<String, String> getSensorValue(String sensorName) {
Map<String,String> sensorValues = new HashMap<String,String>();
registerSensor(sensorName);
sensorValues.put("x","25");
sensorValues.put("y","26");
sensorValues.put("z","27");
return sensorValues;
}
Almost as Rich said in his answer, but your method returns a Map which cannot be cast to a HashMap. Try this
Map<String, String> map = sensVal.getSensorValue("...");
Or alternatively change your getSensorValue method so that it returns a HashMap
HashMap sensValues = new HashMap();
Set mapSet = (Set) sensValues.entrySet();
Iterator mapIterator = mapSet.iterator();
while (mapIterator.hasNext()) {
Map.Entry mapEntry = (Map.Entry) mapIterator.next();
String keyValue = (String) mapEntry.getKey();
String value = (String) mapEntry.getValue();
System.out.println("Key : " + keyValue + "= Value : " + value);
}
Also you can try pass by reference aproach,
void main(){
public static HashMap<String, String> sensValues = new HashMap<String, String>();
AllSensors sensVal = new AllSensors();
sensVal.setSensorValue(sensValues ,"orientation");
String something = sensValues.get("x");
}
public void setSensorValue(Map<String, String> sensorValues, String sensorName) {
registerSensor(sensorName);
sensorValues.put("x","25");
sensorValues.put("y","26");
sensorValues.put("z","27");
}