记录一下Collectors.toMap()的坑

遇到的问题:

在用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 keyMapper,
                                    Function valueMapper) {
        return toMap(keyMapper, valueMapper, throwingMerger(), HashMap::new);
    }

发现是throwingMerger()方法抛出的异常,那么看一下何时会调用throwingMerger()方法

public static >
    Collector toMap(Function keyMapper,
                                Function 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 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;
    }

 

你可能感兴趣的:(线上问题定位(一些坑))