一、问题
在使用Collectors.toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper)(两个参数的)时,如果 key 有重复,则会报异常(IllegalStateException)。
二、分析
Collectors.toMap()是有三个重载方法(2个参数,3个参数,4个参数),如下所示:
keyMapper:Key 的映射函数
valueMapper:Value 的映射函数
mergeFunction:当 Key 冲突时,调用的合并方法
mapSupplier:Map 构造器,在需要返回特定的 Map 时使用
1、toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper);
2、toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper,
BinaryOperator<U> mergeFunction);
3、toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper,
BinaryOperator<U> mergeFunction, Supplier<M> mapSupplier);
①第一个,如果key冲突了,会默认抛出异常
public static <T, K, U>
Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,
Function<? super T, ? extends U> valueMapper) {
return toMap(keyMapper, valueMapper, throwingMerger(), HashMap::new);
}
②第二个,如果key冲突了,可以按照指定的要求进行合并(取第一个还是最后一个)
public static <T, K, U>
Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,
Function<? super T, ? extends U> valueMapper,
BinaryOperator<U> mergeFunction) {
return toMap(keyMapper, valueMapper, mergeFunction, HashMap::new);
}
③第三个可以自定义异常方法和 Map 类型
public static <T, K, U, M extends Map<K, U>>
Collector<T, ?, M> toMap(Function<? super T, ? extends K> keyMapper,
Function<? super T, ? extends U> valueMapper,
BinaryOperator<U> mergeFunction,
Supplier<M> mapSupplier) {
BiConsumer<M, T> accumulator
= (map, element) -> map.merge(keyMapper.apply(element),
valueMapper.apply(element), mergeFunction);
return new CollectorImpl<>(mapSupplier, accumulator, mapMerger(mergeFunction), CH_ID);
}
举例如下:
三、解决方法
避免出现重复时报异常,建议选用第二个带3个参数的 toMap 方法(一般取前面value的值,或者取后面放入的 value 值则覆盖先前的 value 值)。
1、选用重复 key 中第一个 value 值
Map<String, Object> result = list.stream().flatMap(m -> m.entrySet().stream())
.collect(Collectors.toMap(m -> m.getKey(), m -> m.getValue(), (v1, v2) -> v1));
2、选用重复 key 中最后一个 value 值 (若重复 key 元素有2个则取第二元素的 value,若有3个则取第三个的 value,…)
Map<String, Object> result = list.stream().flatMap(m -> m.entrySet().stream())
.collect(Collectors.toMap(m -> m.getKey(), m -> m.getValue(), (v1, v2) -> v2));
3、指定取哪个value值或哪种类型的value值(具体的实践根据具体的业务来操作数据即可)
4、直接返回一个给定的默认值
四、注意事项
1、key 不能有重复,如果重复则需要使用合并函数取默认值,否则会报错,因为 Map 的 key 不能重复。 2、合并函数有两个参数,第一个参数是重复数据中的第一个元素,第二个参数是重复数据中的最后一个元素,可以用来返回默认值。 3、使用合并函数可以配合排序函数,根据排序规则正序、倒序,取每组重复数据中最近或最远的一条数据,用来处理适当的业务。(上面没有举例,自行验证)