This is possible using the mergeFunction parameter of Collectors.toMap(keyMapper, valueMapper, mergeFunction):
Map<String, String> phoneBook =
people.stream()
.collect(Collectors.toMap(
Person::getName,
Person::getAddress,
(address1, address2) -> {
System.out.println("duplicate key found!");
return address1;
}
));
mergeFunction is a function that operates on two values associated with the same key. adress1 corresponds to the first address that was encountered when collecting elements and adress2 corresponds to the second address encountered: this lambda just tells to keep the first address and ignores the second.
This is possible using the mergeFunction parameter of Collectors.toMap(keyMapper, valueMapper, mergeFunction):
Map<String, String> phoneBook =
people.stream()
.collect(Collectors.toMap(
Person::getName,
Person::getAddress,
(address1, address2) -> {
System.out.println("duplicate key found!");
return address1;
}
));
mergeFunction is a function that operates on two values associated with the same key. adress1 corresponds to the first address that was encountered when collecting elements and adress2 corresponds to the second address encountered: this lambda just tells to keep the first address and ignores the second.
As said in JavaDocs:
If the mapped keys contains duplicates (according to
Object.equals(Object)), anIllegalStateExceptionis thrown when the collection operation is performed. If the mapped keys may have duplicates, usetoMap(Function keyMapper, Function valueMapper, BinaryOperator mergeFunction)instead.
So you should use toMap(Function keyMapper, Function valueMapper, BinaryOperator mergeFunction) instead. Just provide a merge function, that will determine which one of duplicates is put in the map.
For example, if you don't care which one, just call
Map<String, String> phoneBook = people.stream().collect(
Collectors.toMap(Person::getName, Person::getAddress, (a1, a2) -> a1));
java - handle duplicate key in Collectors.toMap() function - Stack Overflow
Improve Collectors.toMap(Function,Function) error message for duplicate keys
Java 8 -> Collectors.toMap -> Duplicate key - Stack Overflow
java - Duplicate key (attempted merging values x and x) - Stack Overflow
@Aomine: solution looks good and works for me too. Just wanted to confirm that with this it iterates twice right ?? Cause with simple solution like below it iterates only once but achieve what is required.
Map<String, String> myMap = new HashMap<>();
persons.forEach(item -> {
if(myMap.containsKey(item.getName()))
{/*do something*/}
else
myMap.put(item.getName(), item.getAddress());
});
if you want to access the whole person object in the merge function then pass Function.identity() for the valueMapper:
Map<String, Person> myMap =
persons.stream()
.collect(toMap(p -> p.getName(),
Function.identity(), // or p -> p
(p1, p2) -> { /* do logic */ }));
But as you can see the resulting map values are Person objects, if you still want a Map<String, String> as a result and still access the whole Person object in the mergeFunction then you can do the following:
persons.stream()
.collect(toMap(p -> p.getName(), Function.identity(),(p1, p2) -> { /* do logic */ }))
.entrySet()
.stream()
.collect(toMap(Map.Entry::getKey, p -> p.getValue().getAddress()));
To avoid this error, you need to take one of the duplicate entries for example, to do this you need:
.collect(Collectors.toMap(Rule::getId, Rule::getCableType, (r1, r2) -> r1));
It is also worth noting that prior to the .collect you may want to consider a .sorted(Comparator.comparing(rule -> rule.cableType)) or something like that, so that way you can be intentional about which values are kept in a duplicate key situation.
The answer from @Youcef above surely gets rid of the exception, but the value selected for the duplicate key is based on whatever order the list is in currently.
The pramodh's answer is good if you want to map your value to 1. But in case you don't want to always map to a constant, the use of the "merge-function" might help:
Map<Integer, Integer> map1 = Files.lines(Paths.get(inputFile))
.map(line::trim())
.map(Integer::valueOf)
.collect(Collectors.toMap(x -> x, x -> 1, (x1, x2) -> x1));
The above code is almost the same as posted in the question. But if it encounters a duplicate key, instead of throwing an exception, it will solve it by applying the merge function, by taking the first value.
The code will run if there are no duplicates in the file.
Map<Integer, Integer> map1 = Files.lines(Paths.get(inputFile))
.map(String::trim)
.map(Integer::valueOf)
.collect(Collectors.toMap(x -> x, x -> 1));
If there are duplicates use the following code to get the total number of occurrences in the file for that key.
Map<Integer, Long> map1 = Files.lines(Paths.get(inputFile))
.map(String::trim)
.map(Integer::valueOf)
.collect(Collectors.groupingBy(x -> x, Collectors.counting());