Is there a way to define a HashMap that has another HashMap as the value without warning?
I mean if I use generics I would have to define:
HashMap<Integer, HashMap<Integer, HashMap<Integer, HashMap<Integer,HashMap etc>> map = new HashMap<>();
Is the correct/only way to do it via the followin?
HashMap<Integer, HashMap> map = new HashMap<Integer, HashMap>();
Update based on comments:
I am just reviewing generics and I was under the impression that it is not uncommon to have a hashmap as a value of another hashmap.
Update based on #JimGarrison comment:
Using a hash of hashes is a very common structure in other languages so I am surprised that I need to actually give some specific use case in order for my question to make sense. If I need to give a real example that this could be used, one would be to e.g. navigate through some hierarchical structure. So we could "mimic" a tree.
You might find F-bound types useful, at least from a theoretical point of view. In your case, this might be:
class FBoundedMap<K> extends HashMap<K, FBoundedMap<K>> {
}
Then you could use it this way:
FBoundedMap<Integer> map = new FBoundedMap<>();
FBoundedMap<Integer> inner1 = new FBoundedMap<>();
map.put(1, inner1);
FBoundedMap<Integer> inner2 = new FBoundedMap<>();
map.put(2, inner2);
FBoundedMap<Integer> innerMost1 = new FBoundedMap<>();
inner1.put(11, innerMost1);
FBoundedMap<Integer> innerMost2 = new FBoundedMap<>();
inner2.put(22, innerMost2);
System.out.println(map); // {1={11={}}, 2={22={}}}
You could only store empty maps at the end, and maps of maps in the middle, so the only practical use I see to this is to store data in the keys (in this case these would be Integers) and use the values to keep references to children nodes of a tree structure.
Another way would be to let the values be of any type, including HashMap. This way, you could store maps as values of other maps. In this case, you'd need to declare your maps as:
Map<Integer, Object> map = new HashMap<>();
Map<Integer, Object> inner1 = new HashMap<>();
map.put(1, inner1);
Map<Integer, Object> inner2 = new HashMap<>();
map.put(2, inner2);
Map<Integer, Object> innerMost1 = new HashMap<>();
inner1.put(11, innerMost1);
Map<Integer, Object> innerMost2 = new HashMap<>();
inner2.put(22, innerMost2);
System.out.println(map); // {1={11={}}, 2={22={}}}
Of course, if you need to get a value, you'd need to cast:
Map<Integer, Object> value = (Map<Integer, Object>) map.get(1);
System.out.println(value); // {11={}}
Related
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);
If ConcurrentHashMap contains Map then, is Internal Values Map also behave Concurrent or not?
The following is my map object
ConcurrentHashMap<String, Map<String, Map<String, String>>> applicationDataMap =
new ConcurrentHashMap<>();
The variable declaration here only uses the Map interface. You can add any Map to this, whether concurrent or not. If you require all of the contained maps to be concurrent, you must declare them as such:
ConcurrentHashMap<String, ConcurrentHashMap<String, ConcurrentHashMap<String, String>>> applicationDataMap = new ConcurrentHashMap<>();
You could put any type of Map in applicationDataMap.
E.g.:
Map<String, String> innerInnerMap = new TreeMap<>();
Map<String, Map<String, String>> innerMap = new HashMap<>();
innerMap.put("innerKey", innerInnerMap);
applicationDataMap.put("key", innerMap);
There's nothing protecting these inner maps from being concurrently accessed by more than one thread. If you want to ensure their validity, you'd have to handle it explicitly.
I have map of maps
Map<String, Map<String,Integer>> outerMap = new HashMap<String, Map<String, Integer>>();
and I want to put some values to inner map. Is that correct way? Or it can be done better?
class SampleMap {
Map<String, Map<String, Integer>> outerMap = new HashMap<String, Map<String, Integer>>();
public void add(String outerKey, String innerKey, Integer value) {
Map<String, Integer> tempMap = new HashMap<String, Integer>();
if (outerMap.size() > 0)
tempMap = outerMap.get(outerKey);
tempMap.put(innerKey, value);
outerMap.put(key, tempMap);
}
}
You can improve the code by avoiding the creation of a new inner map eagerly, until the point when you know that you must create it.
In addition, if you know that the inner map instance came from the outer map, you don't have to spend time putting it back where it came from.
public void add(String outerKey, String innerKey, Integer value) {
Map<String, Integer> tempMap
if (outerMap.containsKey(outerKey)) {
tempMap = outerMap.get(outerKey);
} else {
tempMap = new HashMap<String, Integer>();
outerMap.put(outerKey, tempMap);
}
tempMap.put(innerKey, value);
}
Technically there is nothing wrong in your code (except a minor improvement suggested by dasblinkenlight), but is map of maps what you really need?
If you want to read/write values by two keys, probably it's better to create map from pair of two keys (MultiKey or Pair implementation can be used) or another data structure (see this comment for details https://stackoverflow.com/a/3093993/554281)
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.
I am trying to run a very simple program, and I'm stuck on the basics of declaring the nested lists and maps.
I'm working on a project which requires me to store polynomials into an ArrayList.
Each polynomial is named, so I want a key/value map to pull the name of the polynomial (1, 2, 3 etc.) as the key, and the actual polynomial as the value.
NOW the actual polynomial requires key values as well because the nature of this program requires that the exponent be associated with the coefficient.
So for example I need an ArrayList of polynomials, say the first one is a simple:
polynomial 1: 2x^3
the array list contains the whole thing as a map, and the map contains key: polynomial 1 and value: is a Map... with the 2 and 3 being key/values.
The code I have is below but I'm not 100% on how to format such nested logic.
public static void main(String[] args) throws IOException{
ArrayList<Map> polynomialArray = new ArrayList<Map>();
Map<String, Map<Integer, Integer>> polynomialIndex = new Map<String, Map<Integer, Integer>>();
String filename = "polynomials.txt";
Scanner file = new Scanner(new File(filename));
for(int i = 0; file.hasNextLine(); i++){
//this will eventually scan polynomials out of a file and do stuff
}
EDIT:
Updated the key/value in Map, still having issues.
The code above is giving me the following error:
Cannot instantiate the type Map<String,Map<Integer,Integer>>
So how then do I go about doing this or am I just going about this all the wrong way?
You can't instantiate new Map<String, Map<Integer, Integer>>() because java.util.Map is an interface (it doesn't have a constructor). You need to use a concrete type like java.util.HashMap:
Map<String, Map<Integer, Integer>> polynomialIndex = new HashMap<String, Map<Integer, Integer>>();
Also, if you're using Java 7 or above, you can use generic type inference to save some typing:
Map<String, Map<Integer, Integer>> polynomialIndex = new HashMap<>();
This is incorrect:
Map<String, Map<Integer>> polynomialIndex = new Map<String, Map<Integer>>();
Maps need to have two parameters and your nested map Map<Integer> only has one. I think you're looking for something like:
Map<String, Map<Integer, Integer>> polynomialIndex = new Map<String, Map<Integer, Integer>>();
Or it may be best done separate.
Map<String, Map> polynomialIndex = new Map<String, Map>();
Map<Integer, Integer> polynomialNumbers = new Map<Integer, Integer>();
With this you can just put the numbers in the polynomailNumbers Map then use that in polynomialIndex.