The way to instantiate map<String, List<String>> in Java - java

I would like to instantiate Map<String, List<String>> in Java,
I tried
Map<String, List<String>> foo = new <String, List<String>>();
and
Map<String, List<String>> foo = new <String, ArrayList<String>>();
None of them work. Does any one know how to instantiate this map in Java?

new HashMap<String, List<String>>();
or as gparyani commented:
new HashMap<>(); // type inference
Note: each entry needs to be given an instantiated List as a value. You cannot get("myKey").add("some_string_for_this_key"); the very first time you get() a List from it.
So, fetch a List, check if it's null.
If it's null, make a new list, add the string to it, put the List back.
If it's anything but null, add to it, or do what you want.

You forgot to mention the class. Map here is the reference type and is an Interface. HashMap on the other side of equals specifies the actual type of the Object created and assigned to the reference foo.
Map<String, List<String>> foo = new HashMap<String, List<String>>();
The actual type specified (HashMap here) must be assignable to the reference type (Map here) i.e. if the type of reference is an Interface, the Object's type must implement it. And, if the type of the reference is a Class, the Object's type must either be the same class or its subtype i.e. it extends from it.
From Java 7 onwards, you can use a shorthand like
Map<String, List<String>> foo = new HashMap<>();
Your second way of instantiation is not recommended. Stick to using List which is an Interface.
// Don't bind your Map to ArrayList
new TreeMap<String, ArrayList<String>>();
// Use List interface type instead
new TreeMap<String, List<String>>();

Map is an interface. You have to tell Java which concrete Map class you want to instantiate.
Map<String, List<String>> foo = new HashMap<String, List<String>>();
or
Map<String, List<String>> foo = new TreeMap<String, List<String>>();
etc.

Related

put is not applicable for HashMap type

Below is my code snippet
Map<Object, Object> gobalMap = new HashMap<Object, Object>();
Map<String, Map<String, Integer>> mp = new HashMap<String, Map<String, Integer>>();
gobalMap.put("mp",mp );
((Map<String, Map<String, Integer>>)gobalMap.get("mp")).put("A", new HashMap<String, Integer>().put("A", 1));
error:
The method put(String, Map<String,Integer>) in the type Map<String,Map<String,Integer>> is not applicable for the arguments (String, Integer)
May I know where am doing wrong ..?
new HashMap<String, Integer>().put("A", 1)
This returns an Integer. But you want to add this to an object which stores Maps and not Integer. So that's not possible. Also as Thomas explained in the comments, your code would not work even if it compiled because put returns the previous value of the map so you will receive a NullPointerException.
I would recommend restructuring your code to make it more readable and to also make it work:
Map<Object, Object> gobalMap = new HashMap<Object, Object>();
Map<String, Map<String, Integer>> mp = new HashMap<String, Map<String, Integer>>();
gobalMap.put("mp",mp );
HashMap<String, Integer> aMap = new HashMap<>();
aMap.put("A", 1);
((Map<String, Map<String, Integer>>)gobalMap.get("mp")).put("A", aMap);
As others have already stated new HashMap<String, Integer>().put("A", 1) returns an Integer (the previously mapped value for key "A" so null in this case) and that is not a suitable value for a Map<String, Map<String, Integer>>.
You're creating a suitable map but don't actually put it into the map so the reference to that map is lost.
Since you're probably trying to only create a nested map if it doesn't exist already try this:
((Map<String, Map<String, Integer>>)gobalMap.get("mp"))
.computeIfAbsent( "A", k -> new HashMap<String, Integer>())
.put("A", 1);
This does the following:
get and cast the map from globalMap (if you'd not be sure this can't return null you could use computeIfAbsent() here as well)
get the nested map for key "A" and if it doesn't exist create a new one, add and return it
put the value 1 for key "A" into the nested map
new HashMap<String, Integer>().put("A", 1) returns an integer, because when you put into a hashmap, you get back the previous value held by that key. As such it cannot be the value in a Map<String,Map<String,Integer>>.
Perhaps you meant to cast gobalMap to a Map<String,Map<String,Integer>>. But you are actually casting gobalMap.get("mp") to a Map<String, Map<String, Integer>>.
This, on the other hand, would compile:
((Map<String, Integer>) gobalMap.get("mp")).put("A", new HashMap<String, Integer>().put("A", 1));
though I'm not sure it does anything useful.
you missed the bracket. correct code will be:
((Map<String, Map<String, Integer>>)gobalMap.get("mp")).put("A", new HashMap<String, Integer>()).put("A", 1);

How to correctly define a multidimensional generalized Collection in Java?

For example, I want to create a map that is a map of a map of a map. So I have declared the map as so. From a resultset I want to create a JSON object.
Map<String, Map<String, Map<String, String>>> data = new LinkedHashMap<String, Map<String, Map<String, String>>>();
I could define as
Map<String, Object> map = new LinkedHashMap<String, Object>();
however I need to put items one at a time so I get the map I want and put it in. Then the same the following iterations so I would have to cast the object to the map which leaves unchecked warnings.
Is there a better way of declaration of this type of Collection?
You can use a Google Guava MultiMap, but really you're better off creating a new Object and referencing the entire collection of data from the single key.
public class MyObjectData {
private String string1;
private Map<String, String> map;
// Getters and setters
}
Then your map becomes Map<String, MyObjectData>

difference between Map<?,?> and Map<Object,Object>

when I declare a Map or Map <Object,Object> I can put anything in this Map
Map map = new HashMap();
map.put("");
but if I declare it as Map <?,?> I can put nothing in it
Map<?,?> map = new HashMap();
map.put("");
it will goes wrong why ?
Map<?,?> map = new HashMap<Integer, Integer>(); // compiles just fine!
? represents some fixed but unknown type. You can't put "" in a Map<Integer, Integer>, and a Map<?, ?> is allowed to be any type of Map, including a Map<Integer, Integer>.
In java collection Frame, ? means unknown type. You can only read elements from that, but can not add elements except for NULL value.
So you can compile fine like below:
Map<?,?> map = new HashMap();
map.put(null, null);
For this snippet code:
Map<?,?> map = new HashMap();
Map<?,?> means a Map typed to an unknown type.
The question mark (?), called the wildcard,the wildcard means "the value type parameter could be anything", it doesn't mean "you can use this as if it were anything you want it to be".
For more info go to link

Why i can't put string into a field which is something that extends Object

I have a map like the one below
final Map<String, ? extends Object> map
Can anyone tell me why this operation is not possible..?
productMap.put("min", String.valueof(34));
What should be the turnaround...
You can't add any object to a Map because the compiler knows the value is some class which extends Object, but doesn't know which one.
Map<String, ? extends Object> map = new HashMap<String, Integer>();
Object val = map.get("min"); // this is ok.
map.put("min", Integer.toString(34)); // not allowed.
Instead you can use
Map<String, Object> map = new HashMap<String, Object>();
Object val = map.get("min"); // this is ok.
map.put("min", Integer.toString(34)); // is ok.
The wildcard provides flexibility (you can now assign a HashMap<String, String> or a HashMap<String, Integer> to map) in exchange for a condition: you cannot write to map, because it doesn't know what the actual class of the values will be.
See here for a good tutorial.
You've told the compiler that the map values will be some specific subtype of Object. ? could be anything -- you could do:
Map<String,? extends Object> map = new HashMap<String,Integer>();
So String might be invalid.
You probably want the simpler Map which does allow any value.
Or you can "cheat" and do a cast which hides the generic type:
((Map)productMap).put("min", String.valueof(34));
But that trick is not best practice & to be used sparingly if at all.
By declaring the map as Map<String, ? extends Object>, you state that the second type is "anything which inherits from object". This is equivalent to declaring the map as Map<String, ?>. This declaration enables assignments like
final Map<String, ? extends Object> map = new HashMap<String, Integer>();
I think this example makes it clear why the compiler forbids inserting strings into the map: The value type is unspecified in the declaration.

Java Casting Problem

Why isn't a Map<String,List<SomeBean>> castable to Map<String,List<?>>?
What I'm doing now is this:
Map<String, List<SomeBean>> fromMap = new LinkedHashMap<String, List<SomeBean>>();
/* filling in data to fromMap here */
Map<String,List<?>> toMap = new LinkedHashMap<String, List<?>>();
for (String key : fromMap.keySet()) {
toMap.put(key, fromMap.get(key));
}
In my opinion there should be a way around this manual transformation, but I can't figure out how. Any Ideas?
The cast is invalid because in Map<String,List<?>> you can put List<String> and List<WhatEver>, but not in Map<String, List<SomeBean>>.
For instance:
//List<SomeBean> are ok in both lists
fromMap.put("key", new ArrayList<SomeBean>());
toMap.put("key", new ArrayList<SomeBean>());
//List<String> are ok in Map<String,List<?>>, not in Map<String, List<SomeBean>>
fromMap.put("key", new ArrayList<String>()); //DOES NOT COMPILE
toMap.put("key", new ArrayList<String>());
To simplify your code, you may use the appropriate constructor to simplify your code:
Map<String, List<SomeBean>> fromMap = new LinkedHashMap<String, List<SomeBean>>();
Map<String,List<?>> toMap = new LinkedHashMap<String, List<?>>(fromMap);
Not realy an answer to your question, but as an extra: I would not use keyset here... If you want to iterate through all the elements of a map, use the entrySet() method. Its faster because it does not require the key-value lookup for each element.
for (Map.Entry<String, List<SomeBean>> entry : fromMap.entrySet()) {
toMap.put(entry.getKey(), entry.getValue());
}
If you really want to, you could cast to a raw Map (but what you want is not type safe):
Map<String,List<?>> toMap = (Map) new LinkedHashMap<String, List<String>>();
When assigning to a Map, where K and V are not wildcard parameters, the Map being assigned must have exactly the same K and V. In your case, V must be exactly List<?>.
The workaround it to use a wildcard V.
Map<String, ? extends List<?>> map = new LinkedHashMap<String, List<String>>();
Because the V you are assigning to is a wildcard, the V being assigned must only be assignable to V (rather than being exactly V).

Categories

Resources