美文网首页
Collectors.toMap源码解析

Collectors.toMap源码解析

作者: 无实践无真知 | 来源:发表于2019-05-15 10:56 被阅读0次

一个bug的由来

用过java 8 的同学都知道在 list.stream() 可以省去很多代码 java流编程操作起来很方便。但是之前在使用流的时候会出现莫名其妙的bug
//读者可以试一下下面这段代码
  List<User> list = new ArrayList<>();
        User user = new User();
        user.setIdNumber("123");
        user.setName("1235");
        list.add(user);
        User user1= new User();
        user1.setIdNumber("123");
        user1.setName(null);
        list.add(user1);

        Map<String, String> collect = list.stream().collect(Collectors.toMap(User::getIdNumber, User::getName, (a, b) -> a));
        System.out.println(collect);

        //随便写的合并规则 意思是:如果key存在value与其对应 则新进来值的时候 保留旧值
运行结果:
Exception in thread "main" java.lang.NullPointerException
    at java.util.HashMap.merge(HashMap.java:1225)
    at java.util.stream.Collectors.lambda$toMap$58(Collectors.java:1320)
    at java.util.stream.ReduceOps$3ReducingSink.accept(ReduceOps.java:169)
    at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1382)
    at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
    at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
    at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
    at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
    at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)
    at com.uloo.cn.Main.main(Main.java:43)

//虽然 读者可能觉得我在前面的代码里面刻意设置了null值,但是从数据库中读取数据你是没办法知道下一步运行是否出错
// 下面点进Collectors.toMap() 这个方法 你会发现 这里用了很多泛型,但是这里你仔细看一下发现很简单:这个函数的第一个参数是一个接口T是转换的原始类型 K是目标类型 例如 user -> userId 第二个参数是类似。

 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);
    }
//接下来进入重载方法 toMap 又是一长坨的泛型,前两个参数已经解释过了不在赘述,这里调用了java8新增的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);
    }
//点进入这个merge前面两行直接对传入的值进行限制 如果为空则抛出空指针

 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;
    }

相关文章

网友评论

      本文标题:Collectors.toMap源码解析

      本文链接:https://www.haomeiwen.com/subject/rwbuaqtx.html