Map/HashMap Casting? - java

So I have a method, setContainerSummaryMap, which takes in a Map<String, Map<String, Integer>>.
I also have a HashMap<Long, HashMap<String, Integer>>, called contIdDestQuanMapSoFar, which I am going to convert into a HashMap<String, HashMap<String, Integer>> with a HashMap<Long, String>, named contIdToScanIdMap, that maps the keys to one another. This method is below:
public HashMap<String, HashMap<String, Integer>> convertContSummaryMap() {
HashMap<String, HashMap<String, Integer>> toRet = new HashMap<String, HashMap<String, Integer>>();
for (Entry<Long, HashMap<String, Integer>> entry : contIdDestQuanMapSoFar.entrySet()) {
toRet.put(contIdToScanIdMap.get(entry.getKey()), entry.getValue());
}
return toRet;
}
The problem is, when I call the method setContainerSummaryMap(currentPlan.convertContSummaryMap()), I get an error, saying that it is not applicable for the arguments HashMap<String, HashMap<String, Integer>>. How would I modify the datatypes for this to work? Thanks.

You can redefine your setContainerSummaryMap method:
public void setContainerSummaryMap(Map<String, ? extends Map<String, Integer>> map)
or, as Louis already suggested change the return type of your convertContSummaryMap to match:
public HashMap<String, Map<String, Integer>> convertContSummaryMap()

To make this work, the type of toRet must be HashMap<String, Map<String, Integer>>. As #SLaks stated, a HashMap<String, Map> is not the same as a HashMap<String, HashMap>.
Of course, the Maps you'll actually put into it will still be HashMaps.

Related

Map of Map iteration

Im storing 2 map with different structure in single map like below,
Map<String, List<String>> colMap = new HashMap<String, List<String>>();
Map<String, String> appMap = new HashMap<String, String>();
// colMap assigning some values
// appMap assigning some values
Map<String, Map> mainMap = new HashMap<String, Map>();
mainMap.put("appMap", appMap);
mainMap.put("colMap", colMap);
I want to get map one by one and iterate the map.
If I try get map like below, getting error,
.......
Map colMap = map.get("colMap");
for(Entry<String, List<String>> entry : colMap.entrySet())
Error: Type mismatch: cannot convert from element type Object to Map.Entry<String,List<String>>
Why not just create a simple container POJO class (or record in Java 16+) for the two maps instead of mainMap and keep the relevant type-safety which to do it Java-way?
public class MapPojo {
private final Map<String, List<String>> colMap;
private final Map<String, String> appMap;
public MapPojo(Map<String, List<String>> colMap, Map<String, String> appMap) {
this.colMap = colMap;
this.appMap = appMap;
}
// getters, etc.
}
MapPojo mainMap = new MapPojo(colMap, appMap);
Error you are getting because when you are doing map.get operation your reference is Just Map without any Generics which will treated as Object class's reference. You should use generics like below and it will work -
Map<String, List<String>> colMap = map.get("colMap");
for(Entry<String, List<String>> entry : colMap.entrySet())

Updating a certain value of an hashmap containing an hashmap in Java

I have an outerMap which contains an innerMap for each key it got. At first, every innerMap is the same (here, they contain {1=1}.
I want to change the value of one certain innermap, for a certain key.
Here is my code:
public class HelloWorld
{
public static void main(String args[]){
HashMap<String, HashMap<String, Integer>> outerMap = new HashMap<String, HashMap<String, Integer>>();
HashMap<String, Integer> innerMap = new HashMap<String, Integer>();
outerMap.put("1001",innerMap);
outerMap.put("1002",innerMap);
outerMap.put("1003",innerMap);
innerMap.put("1", 1);
//My attempt to change only one innermap;
Map<String, Integer> map_to_change = outerMap.get("1001");
map_to_change.put("1", 0);
//And then I print them to see if it's working;
for(Map.Entry map : outerMap.entrySet() )
{
System.out.println(map.getKey()+" "+map.getValue());
}
}
}
However, the output here is
1003 {1=0}
1002 {1=0}
1001 {1=0}
Which shows that my code changes all innermaps, and not only the one linked with the key "1001".
What can I do?
You are pointing the same innerMap object in the outerMap,
outerMap.put("1001",new HashMap<String, Integer>());//create separate maps
outerMap.put("1002",new HashMap<String, Integer>());
outerMap.put("1003",new HashMap<String, Integer>());
HashMap<String, Integer> innerMap =outerMap.get("1001");//get the map you want to put value
innerMap.put("1", 1);//assign the value
Update:
If you want to retain a copy of Map which you have already created, you can copy and create a new Map from it using putAll method,
outerMap.put("1001",copyMap(innerMap));
outerMap.put("1002",copyMap(innerMap));
outerMap.put("1003",copyMap(innerMap));
copyMap method looks like,
private static HashMap<String, Integer> copyMap(HashMap<String, Integer> innerMap){
HashMap<String, Integer> copiedInnerMap = new HashMap<String, Integer>();
copiedInnerMap.putAll(innerMap);
return copiedInnerMap;
}

Java 8: Transform EnumMap<ExampleEnum, String> to Map<String, Object>

I have a situation where I need to copy my EnumMap<ExampleEnum,String> to Map<String, Object>. Many examples on Stack Overflow shows how to cast from one data type to another but not from enum. I have tried doing it through stream but no luck. Here is my code
private enum Number{
One, Two, Three;
}
final Map<Number, String> map = Collections.synchronizedMap(new EnumMap<Number, String> (Number.class));
populateMap(map);
Map<String, Object> newMap= new HashMap<String, Object>();
Now I want to do something like
newMap.putAll(map);
How can I do it through Stream APIs?
A more concise answer is,
final Map<Number, String> map = Collections.synchronizedMap(new EnumMap<>(Number.class));
Map<String, Object> newMap= new HashMap<>();
map.forEach((key, value) -> newMap.put(key.name(), value));
Map<String, Object> newMap = map.entrySet().stream()
.collect(Collectors.toMap(e -> e.getKey().toString(), Map.Entry::getValue));

Casting Object (which is of type Map<String, String>) to Map<String, Integer>

I have an Object which is of type Map<String, String> which has few entries. I expected to get a ClassCastException while casting this object to Map<String, Integer>. But the cast was successful. Why is it that this did not throw any exception?
Map<String, String> map1 = new HashMap<>();
map1.put("key1", "value1");
map1.put("key2", "value2");
Object o = map1;
Map<String, Integer> map2 = (Map<String, Integer>) o;
Edit: Casting from o not map1.
Generic-checking is made at compile time,while casting checking is done at the time of running the program.So You had got casting exception at run time.
You parse it as Integer.parseInt(String) and put the value into map2.
Are you sure that's right?
Your example fails to compile:
Error:(21, 60) java: incompatible types: java.util.Map<java.lang.String,java.lang.String> cannot be converted to java.util.Map<java.lang.String,java.lang.Integer>
However, changing from map1 to o, does compile:
//...
Object o = map1;
Map<String, Integer> map2 = (Map<String, Integer>) o;
Perhaps you're looking for something like this?
Map<String, String> map1 = new HashMap<>();
map1.put("key1", "1");
map1.put("key2", "2");
Map<String, Integer> map2 = new HashMap<>();
map1.forEach((key,value) -> map2.put(key, Integer.parseInt(value)));

Java excplicit cast of nested maps

Why does this cast work?
import java.util.HashMap;
import java.util.Map;
public class TestMap {
public static void main(String[] args) {
Map<String, Map<String, Map<String, Map<String,Integer>>>> resultMap = new HashMap<>();
Map<String, Object> aMap = new HashMap<String, Object>();
Map<String, Integer> hiddenMap = new HashMap<String, Integer>();
hiddenMap.put("fortytwo", 42);
aMap.put("key", hiddenMap);
resultMap = (Map<String, Map<String, Map<String, Map<String, Integer>>>>) aMap.get("key");
System.out.println(resultMap);
}
}
also this:
Map<String, Map<String, Map<String, Map<String,Map<String,Integer>>>>> resultMap = new HashMap<>();
...
resultMap = (Map<String, Map<String, Map<String, Map<String,Map<String,Integer>>>>>) aMap.get("key");
and so on...
How does this happen that the hidden map which is Map<String, Integer> gets successfully cast to Map<String, Map<String, Map<String, Map<String,Integer>>>> resultMap?
Always prints:
{fortytwo=42}
Also this works (Map instead of Map):
public static void main(String[] args) {
Map<String, Map<String, Map<String, Map<String,Map<String,Integer>>>>> resultMap = new HashMap<>();
Map<String, Map> aMap = new HashMap<String, Map>();
Map<String, Integer> hiddenMap = new HashMap<String, Integer>();
hiddenMap.put("fortytwo", 42);
aMap.put("key", hiddenMap);
resultMap = (Map<String, Map<String, Map<String, Map<String,Map<String,Integer>>>>>) aMap.get("key");
System.out.println(resultMap);
}
EDIT: So as #shizhz says, it is because of Type Erasure of course! So the code above is equivalent to:
Map resultMap = new HashMap();
Map aMap = new HashMap();
Map hiddenMap = new HashMap();
hiddenMap.put("fortytwo", 42);
aMap.put("key", hiddenMap);
resultMap = (Map) aMap.get("key");
Which also works
Because java generics is used at compile time to provide tighter type checks, the type parameter is erased by compiler according Type Erasure rules:
Replace all type parameters in generic types with their bounds or Object if the type parameters are unbounded. The produced bytecode, therefore, contains only ordinary classes, interfaces, and methods.
Insert type casts if necessary to preserve type safety.
Generate bridge methods to preserve polymorphism in extended generic types.
In code Map<String, Map> aMap = new HashMap<String, Map>();, the value in aMap is a raw type Map, which means the compiler has no idea what's the type it contains, when you try to cast a raw type of Map to any generics type of Map like Map<String, Integer>, the best compiler can do is giving you a warning. The generic type is erased at compile time and type cast will be generated when you get value from a generic map, so you can only get a runtime ClassCastException exception if the type mismatchs.
Let's have a look at the following example:
public static void main(String[] args) {
Map map = new HashMap();
map.put("hello", "world");
map.put(new Integer(1), 1);
map.put(new Object(), Lists.newArrayList("hello"));
Map<String, Integer> m = (Map<String, Integer>) map;
System.out.println(m);
Integer i = m.get("hello");// ClassCastException happens at here at runtime
}
I'm trying to convert a Map containing all kinds of keys and values to Map<String, Integer> but there's no compile error, after type erasure, the above code is actually equivalent to:
public static void main(String[] args) {
Map map = new HashMap();
map.put("hello", "world");
map.put(new Integer(1), 1);
map.put(new Object(), Lists.newArrayList("hello"));
Map m = (Map) map;
System.out.println(m);
Integer i = (Integer)m.get("hello");
}
Now you can easily tell why the last line caused ClassCastException.
Since you've declared aMap as Map<String, Object>, the compiler cannot tell if the values won't indeed be of type Map<String, Map<String, Map<String,Integer>>>. It will just give you an "Unchecked cast" warning to let you think about the consequences.
The cast works unless you're actually trying to do something with the values:
resultMap.get("fortytwo").isEmpty();
will result in
Exception in thread "main" java.lang.ClassCastException:
java.lang.Integer cannot be cast to java.util.Map
If you had declared aMap as Map<String, Map<String, Map<String, Map<String, Map<String, Integer>>>>> you wouldn't be able to put hiddenMap in it in the first place.

Categories

Resources