How I use the put() method for Maps in Maps - java

this is my Map in Maps I created
private static Map<Integer, Map<String, String>> directory = new HashMap<>();
and I want to know how I use the put() method for this above.
I tried this for example:
directory.put(5,"Test1","Test2");
but this is not correct. I get the following message by eclipse:
The method put(Integer, Map<String,String>) in the type Map<Integer,Map<String,String>> is not applicable for the arguments (int, String, String)
But I have to hold on to the guidelines for the university. There is a JUnitTest and there is also the put method. Just look how they did this:
addEntry(1, "Name", "Dall", "FirstName", "Karl", "phoneNr", "4711");
and thats my addEntry Method from the university
public static void addEntry(int nrP, String... attrValPairs) throws IllegalArgumentException

Yours is a nested Map, so you need to have a Map object in the value of the outer Map:
if(!directory.containsKey(5)) {
directory.put(5, new HashMap<>());
}
directory.get(5).put("Test1", "Test2");

I would implement it like this
private static final Map<Integer, Map<String, String>> directory = new HashMap<>();
public static void put(Integer key1, String key2, String value) {
Map<String, String> map = directory.get(key1);
if (map == null)
directory.put(key1, map = new HashMap<>());
map.put(key2, value);
}

private static Map<Integer, Map<String, String>> directory = new HashMap<>();
This accepts 2 arguments Integer and Map
So you can only put Integer and Map but here directory.put(5,"Test1","Test2"); you are putting 3 arguements Integer,String and String
Hence this error The method put(Integer, Map<String,String>) in the type Map<Integer,Map<String,String>> is not applicable for the arguments (int, String, String)
To solve your problem I would suggest you to create another map like this
Map<String, String> directory1 = new HashMap<String,String>();
Now put the Strings in this map first like this
directory1.put("Test1","Test2");
and now you can use this
directory.put(5,directory1);

Related

How can I convert a 'Collection<Map<String,String>>' to 'Map<String,String>'?

I want to convert from Collection<Map<String,String>> to Map<String,String>.
When I tried to do this way,
Map<String,String> m = (Map<String,String>)map.values();
where,
map is of type Map<String,Map<String,String>>
I'm getting
java.lang.ClassCastException: java.util.TreeMap$Values cannot be cast to java.util.Map
What is it trying to say? I'm not able to get it and how do I correctly convert from Collection<Map<String,String>> to Map<String,String>?
You can use this small snippet to put all the values into a single map:
Map<String, String> result = new TreeMap<>();
for(Map<String, String> value : map.values()) {
result.putAll(value);
}
Though this will just overwrite duplicate keys with a new value if there are any.
As long as it's collection then you should think as it's collection of objects.
Then proceed the iteration, for each object, you shall put it in the map
public Map<String, String> getMapsFromArrayOfMaps( Collection<Map<String,String>> maps ) {
Map<String, String> result = new HashMap<>();
maps.forEach(map->result.putAll(map));
return result ;
}

Elegant way to create a new map from old one in Java, while keeping the sorting of elements the same

Let's consider the following code:
//...
public Map<String, Integer> getFruits() throws SomeException {
QueryResult[] queryResults = queryFruits();
Map<String, Integer> fruits = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
for (QueryResult qr : queryResults) {
fruits.put(qr.getField("Name").toString(), (Integer) rec.getField("ArticleNumber"));
}
return fruits;
}
//...
public static void main(String args[]) {
App app = new App();
Map<String, Integer> originalFruits = app.getFruits();
System.out.println(originalFruits.keySet());
}
– the result of execution will be
[Apple, banana, cherry, Dragon_Fruit, Papaya ]
After that I'm calling getApprovedFuits() and passing originalFruits to it, along with whiteListedFruitNames:
public Map<String, Integer> getApprovedFruits(Map<String, Integer> fruits, Set<String> whiteListedFruitNames) {
Map<String, Integer> approvedFruits = new TreeMap<>(fruits);
approvedFruits.keySet().retainAll(whiteListedFruitNames);
return approvedFruits;
}
//...
public static void main(String[] args) {
App app = new App();
Map<String, Integer> originalFruits = app.getFruits();
// v
Set<String> whiteListedFruitNames = new HashSet<>(Arrays.asList("Apple",
"banana",
"cherry",
"Dragon_Fruit",
"kiwi",
"Pineapple"));
Map<String, Integer> approvedFruits = getApprovedFruits(originalFruits, whiteListedFruitNames);
System.out.println(approvedFruits.keySet());
}
– the result of the latter println() will look like this:
[Apple, Dragon_Fruit, banana, cherry]
– and I expected to see this:
[Apple, banana, cherry, Dragon_Fruit]
And here is my question: how to make map constructor TreeMap<>(fruits) respect the sorting order of the map that is passed to it? Is there an elegant way to create a new map based on the original one, with the same sorting order?
TreeMap has a constructor from a SortedMap that retains the same Comparator (and thus, the ordering). However, since you're passing your TreeMap as a Map, this constructor is not used - instead, the constructor from a Map is called, and the ordering is lost.
To make a long story short - change getApprovedFruits' signature to use a SortedMap and you should be fine:
public Map<String, Integer> getApprovedFruits
(SortedMap<String, Integer> fruits, Set<String> whiteListedFruitNames) {
Two other options in addition to #Mureinik's answer:
Construct your new TreeMap with an explicit comparator:
Map<String, Integer> approvedFruits = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
approvedFruits.putAll(fruits);
If you're not planning on adding to the resulting map, you can use LinkedHashMap which will simply keep the initial insertion order:
Map<String, Integer> approvedFruits = new LinkedHashMap<>(fruits);

Nested HashMaps and Declaration

I'm trying to experiment with Maps and I have this doubt:
Map<String, Object> input = new LinkedHashMap<String, Object>();
String operator = "in";
String argument = "foo";
String field = "AvailabilityStatus";
Map<String, Object> innerMap = new LinkedHashMap<String, Object>();
innerMap.put(operator, argument);
input.put(field, innerMap);
The function call for the above code is
String output = FunctionA(input);
Seems to work fine but changing the input to:
Map<String, Map<String, Object>> input = new LinkedHashMap<String, LinkedHashMap<String, Object>>();
doesn't let me call the function the same way. The functionA is:
public static String FunctionA(Map<String, Object> filters) throws Throwable {
//logic goes here
}
Aren't the two statements essentially trying to do the same thing?
Alternately, you could make the FunctionA method like this:
public static String FunctionA(Map<String, ? extends Object> filters) throws Throwable{
//logic goes here
}
Doing this will be happy then!
FunctionA(new HashMap<String, LinkedHashMap<String, Object>>());
A Map<String, Map<String, Object>> is not a subtype of Map<String, Object>, even though Map<String, Object>is a subtype of Object.
Indeed, uou can store whatever object you want in the latter, whereas you can only store Map<String, Object> instances in the former. That's why the compiler doesn't let you pass a Map<String, Map<String, Object>> to a method taking a Map<String, Object> as argument.
If it let you do that, the method could store Strings, Integers or Bananas into the map, which would thus ruin the type-safety of the map, supposed to only contain instances of Map<String, Object>.

How to create a map instance variable

I've been trying to create a class that will model a scenario I've come up with. It will involve a map with string keys and values.
I need to create an instance variable used to reference the map object, and a constructor that creates the empty map and assigns it to the map instance variable.
I've been messing around with map objects but not creating a class using them, and I've hit a mental block!
What's the proper way to actually get a map object?
public class TheClass {
private Map<String, String> theMap;
public TheClass() {
theMap = new HashMap<>();
}
}
public class Demo {
Map<String,String> map = null;
public Demo()
{
map = new HashMap<String,String>();
}
}
If you want to use HashMap which is Map implementation you can do it like that:
Map<String, String> map = new HashMap<String, String>();
or
Map<String, String> map = new HashMap<>();
in Java 7.
You can also use other implementations like TreeMap.
You can use the HashMap which is an implementation of Map
http://docs.oracle.com/javase/7/docs/api/java/util/HashMap.html
Map<String,String> map = new HashMap<String,String>();
map.put("key1", "Value1");
map.put("Key2", "Value2");

How to change HashMap<K, V> value type from Object to String?

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);

Categories