Map<String, String> phoneBook = people.stream()
.collect(toMap(Person::getName,
Person::getAddress));
我得到java.lang.IllegalStateException:当找到一个重复的元素时,重复键。
是否有可能忽略这种例外添加值到地图?
当有重复的键时,应该忽略重复的键继续执行。
这可以通过使用collector的mergeFunction参数实现。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是一个对与同一个键相关联的两个值进行操作的函数。address1对应于收集元素时遇到的第一个地址,address2对应于遇到的第二个地址:这个lambda只是告诉保留第一个地址而忽略第二个地址。
对于其他遇到此问题但没有在映射流中重复键的人,请确保keyMapper函数不返回空值。
跟踪这个是非常烦人的,因为当它处理第二个元素时,Exception会说“重复键1”,而1实际上是条目的值而不是键。
在我的情况下,我的keyMapper函数试图在不同的映射中查找值,但由于字符串中的错别字返回空值。
final Map<String, String> doop = new HashMap<>();
doop.put("a", "1");
doop.put("b", "2");
final Map<String, String> lookup = new HashMap<>();
doop.put("c", "e");
doop.put("d", "f");
doop.entrySet().stream().collect(Collectors.toMap(e -> lookup.get(e.getKey()), e -> e.getValue()));
正如在JavaDocs中所说:
如果映射的键包含重复项(根据
Object.equals(Object))时,当异常时抛出IllegalStateException
执行收集操作。如果映射的键可能有
重复,使用toMap(Function keyMapper, Function valueMapper, BinaryOperator mergeFunction)代替。
所以你应该使用toMap(Function keyMapper, Function valueMapper, BinaryOperator mergeFunction)来代替。只需提供一个合并函数,它将确定将哪个副本放入映射中。
例如,如果你不关心是哪个,打电话就可以了
Map<String, String> phoneBook = people.stream().collect(
Collectors.toMap(Person::getName, Person::getAddress, (a1, a2) -> a1));
来自alaster的答案对我帮助很大,但如果有人试图对数据进行分组,我想添加有意义的信息。
例如,如果您有两个订单,每个订单的代码相同,但产品数量不同,并且您希望将数量相加,您可以执行以下操作:
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}
或者,在javadocs中,你可以组合地址:
Map<String, String> phoneBook
people.stream().collect(toMap(Person::getName,
Person::getAddress,
(s, a) -> s + ", " + a));