使用流生成地图时忽略重复项

问题

Map<String, String> phoneBook=people.stream()
                                    .collect(toMap(Person::getName, Person::getAddress));

重复发生时,我得到重复的密钥异常。

是否可以忽略在重复发生时将值添加到map?

当存在重复时,它应该继续忽略该重复键。


#1 热门回答(253 赞)

这可以使用23567450参数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是一个函数,它对与同一个键相关联的两个值进行操作.adress1对应于收集元素时遇到的第一个地址,而adress2对应于遇到的第二个地址:这个lambda只是告诉保留第一个地址并忽略第二个地址。


#2 热门回答(51 赞)

JavaDocs所述:

如果映射的键包含重复项(根据Object.equals(Object)),则在执行集合操作时会抛出IllegalStateException。如果映射的键可能有重复,请使用toMap(函数keyMapper,函数valueMapper,BinaryOperator mergeFunction)。

所以你应该使用toMap(Function keyMapper, Function valueMapper, BinaryOperator mergeFunction)。只需提供合并功能,即确定需要将哪一个重复放入 Map 中。例如,如果你不关心哪一个,只需打电话

Map<String, String> phoneBook = people.stream()
  .collect(Collectors.toMap(Person::getName, Person::getAddress, (p1, p2) -> p1));

#3 热门回答(0 赞)

@alaster的回答对我很有帮助,但如果有人试图对信息进行分组,我想添加一个有意义的信息。

如果你有两个Orders与相同的code但每个产品不同的quantity产品,并且你的愿望是总和,你可以这样做:

List<Order> listQuantidade = new ArrayList<>();
listOrders.add(new Order("COD_1", 1L));
listOrders.add(new Order("COD_1", 5L));
listOrders.add(new Order("COD_1", 3L));
listOrders.add(new Order("COD_2", 3L));
listOrders.add(new Order("COD_3", 4L));

listOrders.collect(Collectors.toMap(Order::getCode, o -> o.getQuantity(), (o1, o2) -> o1 + o2));

结果:

{COD_3=4, COD_2=3, COD_1=9}