遇到的问题:
在用java的拉姆达表达式的时候遇到这么一个坑,
Collectors.toMap()会抛一个异常
Duplicate key xxx,
解决思路:
看源码,一步一步定位问题,看异常是从哪里抛出来的,发现是下面方法抛出来的
private static BinaryOperator throwingMerger() {
return (u,v) -> { throw new IllegalStateException(String.format("Duplicate key %s", u)); };
}
从Collectors.toMap()开始一步一步看调用过程
public static
Collector> toMap(Function super T, ? extends K> keyMapper,
Function super T, ? extends U> valueMapper) {
return toMap(keyMapper, valueMapper, throwingMerger(), HashMap::new);
}
发现是throwingMerger()方法抛出的异常,那么看一下何时会调用throwingMerger()方法
public static >
Collector toMap(Function super T, ? extends K> keyMapper,
Function super T, ? extends U> valueMapper,
BinaryOperator mergeFunction,
Supplier mapSupplier) {
BiConsumer accumulator
= (map, element) -> map.merge(keyMapper.apply(element),
valueMapper.apply(element), mergeFunction);
return new CollectorImpl<>(mapSupplier, accumulator, mapMerger(mergeFunction), CH_ID);
}
看到是这里
mapMerger(mergeFunction)调用的
再往下:发现是map的merge方法,当oldvalue不为空时会执行这个方法,所以当key重复后会把value抛出来,所以我们在用
collectors.tomap方法时,要把选择器参数传入,比如可以这么写:(a,b)->b,意思是当key重复是,返回b,也就是返回新的value,而不是旧的
default V merge(K key, V value,
BiFunction super V, ? super V, ? extends V> remappingFunction) {
Objects.requireNonNull(remappingFunction);
Objects.requireNonNull(value);
V oldValue = get(key);
V newValue = (oldValue == null) ? value :
remappingFunction.apply(oldValue, value);
if(newValue == null) {
remove(key);
} else {
put(key, newValue);
}
return newValue;
}