I am new to Java and I am trying to merge multiple maps with string as key and list as values to produce a new Map.
public class Student {
private String name;
private String country;
//Setters and Getters
}
Now I have an util class to add students to the list based on their country.
public class MapAdder {
static Map<String, List<Student>> studentMap =
new LinkedHashMap<String, List<Student>>();
public static void addToMap(String key, Student student) {
studentMap.computeIfAbsent(key,
k -> new LinkedList<Student>()).add(student);
}
public static Map<String, List<Student>> getStudentMap() {
return studentMap;
}
public static void clearStudentMap() {
studentMap.clear();
}
}
Main Method
public static void main(String[] args) {
Map<String, List<Student>> studentMap1;
Map<String, List<Student>> studentMap2;
Map<String, List<Student>> studentMap3;
MapAdder.addToMap("India", new Student("Mounish", "India"));
MapAdder.addToMap("USA", new Student("Zen", "USA"));
MapAdder.addToMap("India", new Student("Ram", "India"));
MapAdder.addToMap("USA", new Student("Ronon", "USA"));
MapAdder.addToMap("UK", new Student("Tony", "UK"));
studentMap1 = MapAdder.getStudentMap();
MapAdder.clearStudentMap();
MapAdder.addToMap("India", new Student("Rivar", "India"));
MapAdder.addToMap("UK", new Student("Loki", "UK"));
MapAdder.addToMap("UK", new Student("Imran", "UK"));
MapAdder.addToMap("USA", new Student("ryan", "USA"));
studentMap2 = MapAdder.getStudentMap();
MapAdder.clearStudentMap();
Map<String, List<Student>> map3 = Stream.of(studentMap1, studentMap2)
.flatMap(map -> map.entrySet().stream())
.collect(Collectors.toMap(
Entry::getKey,
Entry::getValue
));
}
But when I try to merge both the maps I am getting empty map. Actually, I need to have a map with three keys (India, UK, USA) and their values that are list from multiple maps to be merged w.r.t keys.
First, remove from your code the following calls:
MapAdder.clearStudentMap();
you are clearing the studentMap1
and studentMap2
.
When you do:
studentMap1 = MapAdder.getStudentMap();
you get the memory reference in which the student Map
is stored. When you call the clear
method on that map
studentMap.clear();
you will clear all the Map
entries stored on that same memory reference. In other words, the following statement
studentMap1 = MapAdder.getStudentMap();
does not create a copy of the student Map
, instead it just saves on the variable studentMap1
the memory reference to that Map.
Your Stream method is almost right, change it to:
Map<String, List<Student>> map3 = Stream.of(studentMap1, studentMap2)
.flatMap(map -> map.entrySet().stream())
.collect(Collectors.toMap(
Map.Entry::getKey,
e -> new ArrayList<>(e.getValue()),
(left, right) -> { left.addAll(right); return left; }
));
You need also to add the strategy to be used to deal with the duplicate keys (i.e., the mergeFunction
parameter of the Collectors.toMap
method). In case of duplicated keys we add the Map values into the list of the left key.
Btw drop some of those helper methods IMO they obfuscate the code, and make the addToMap
method more generic by passing the Map
itself as parameter, so that you can reuse that method with different mappers, namely:
public class MapAdder {
public static void addToMap(Map<String, List<Student>> studentMap,
String key, Student student) {
studentMap.computeIfAbsent(key,
k -> new LinkedList<Student>()).add(student);
}
public static void main(String[] args) {
Map<String, List<Student>> studentMap1 = new LinkedHashMap<>();
Map<String, List<Student>> studentMap2 = new LinkedHashMap<>();
Map<String, List<Student>> studentMap3;
MapAdder.addToMap(studentMap1, "India", new Student("Mounish", "India"));
MapAdder.addToMap(studentMap1, "USA", new Student("Zen", "USA"));
MapAdder.addToMap(studentMap1, "India", new Student("Ram", "India"));
MapAdder.addToMap(studentMap1, "USA", new Student("Ronon", "USA"));
MapAdder.addToMap(studentMap1, "UK", new Student("Tony", "UK"));
MapAdder.addToMap(studentMap2, "India", new Student("Rivar", "India"));
MapAdder.addToMap(studentMap2, "UK", new Student("Loki", "UK"));
MapAdder.addToMap(studentMap2, "UK", new Student("Imran", "UK"));
MapAdder.addToMap(studentMap2, "USA", new Student("ryan", "USA"));
Map<String, List<Student>> map3 = Stream.of(studentMap1, studentMap2)
.flatMap(map -> map.entrySet().stream())
.collect(Collectors.toMap(
Map.Entry::getKey,
e -> new ArrayList<>(e.getValue()),
(left, right) -> { left.addAll(right); return left; }
));
}
}