I am a bit new to Java streams and struck in the following issue. I tried many things mentioned on this website and in the various articles but was unable to fix them so posting the question here.
I am creating a Map<String, Object>
using the JavaStreams
within my application and then I pass the value to the Map
with duplicate keys
then it throws the following error:
java.lang.IllegalStateException: Duplicate key namespace:localName (attempted merging values [ONE] and [TWO])
at java.base/java.util.stream.Collectors.duplicateKeyException(Collectors.java:133)
Following is the method that's throwing this error:
public Map<String, Object> toMap() {
final Map<String, Object> map = new HashMap<>();
if (complex != null && complex.size() > 0) {
final Map<String, Object> complexMap = complex.stream()
.flatMap(c -> c.toMap().entrySet().stream())
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
map.put(namespacePrefix.concat(":").concat(localName), complexMap);
} else {
map.put(namespacePrefix.concat(":").concat(localName), text);
}
return map;
}
I tried to make the Object
as List
so that if duplicate values are found then add it to the List
something like this:
List<Object> values = (List<Object>) map.get(namespacePrefix.concat(":").concat(localName));
if (values == null) {
values = new ArrayList<Object>();
}
values.add(text);
map.put(namespacePrefix.concat(":").concat(localName), values);
But this also does not seem to work for me. I want to retain both the values if the key is duplicates because I need all the values within my application. Can someone please explain to me what am I doing wrong here and some idea on how to fix it?
CodePudding user response:
The duplicates are not allowed using Collectors.toMap(Function, Function)
method:
If the mapped keys contains duplicates (according to
Object.equals(Object)
), an IllegalStateException is thrown.
Now it depends what output you prefer:
Map<String, Object>
You need to use
Collectors.toMap(Function, Function, BinaryOperator)
with a merging function that decides, which value should be used when the same keys appear.If the mapped keys contains duplicates (according to Object.equals(Object)), the value mapping function is applied to each equal element, and the results are merged using the provided merging function.
This solution requires knowing what to do with two or more duplicated keys.
Map<String, List<Object>>
You need to use a grouping collector
Collectors.groupingBy(Function)
that groups all values by a key, i.e. former values appear in theList
as value. If the former key was duplicated, the newMap
would appear once and theList
as a value would have multiple elements.Returns a Collector implementing a "group by" operation on input elements of type T, grouping elements according to a classification function, and returning the results in a Map.
This solution adds you an option to identify duplicated fields and decide later on what to do with such values.
CodePudding user response:
This is the problematic line:
final Map<String, Object> complexMap = complex.stream().flatMap(c -> c.toMap().entrySet().stream()).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
The error is telling you that at least some of the maps in complex
have keys in common.
You either need to use Collectors.groupingBy
, which yields a list of items per key:
final Map<String, List<Object>> complexMap = complex.stream().flatMap(c -> c.toMap().entrySet().stream()).collect(Collectors.groupingBy(Map.Entry::getKey, mapping(Map.Entry::getValue, Collectors.toList())));
or use the overload of Collectors.toMap
which takes a merging function, allowing you to specify how duplicated keys should be handled.