IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 解决Java `Collectors.toMap` 方法 value为null不支持的问题 -> 正文阅读

[Java知识库]解决Java `Collectors.toMap` 方法 value为null不支持的问题

解决Java Collectors.toMap 方法 value为null不支持的问题

问题描述

在需要把List转换为Map时,通常会使用到Collectors.toMap 方法来转换,但如果转换后的Map的Value有null 则执行时会抛出NullPointerException 异常。

演示代码:

   static class Data{
        int key;
        String value;

        public Data(int key, String value) {
            this.key = key;
            this.value = value;
        }
    }

  @Test
    public void test_toMap(){
        List<Data> dataList = List.of(
            new Data(1,"A"),
            new Data(2,"B"),
            new Data(3,"C"),
            new Data(4,null),
            new Data(5,null)
            );
        Map<Integer,String> dataMap = dataList.stream().collect(Collectors.toMap(item->item.key,item->item.value));

    }

执行的异常内容:

java.lang.NullPointerException
	at java.base/java.util.Objects.requireNonNull(Objects.java:221)
	at java.base/java.util.stream.Collectors.lambda$uniqKeysMapAccumulator$1(Collectors.java:176)
	at java.base/java.util.stream.ReduceOps$3ReducingSink.accept(ReduceOps.java:169)
	at java.base/java.util.AbstractList$RandomAccessSpliterator.forEachRemaining(AbstractList.java:720)
	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
	at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
	at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913)
	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
	at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:511)

原因

Collectors.toMap 有实际有两个实现

  • 第一个实现
public static <T, K, U>
    Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,
                                    Function<? super T, ? extends U> valueMapper) {
        return new CollectorImpl<>(HashMap::new,
                                   uniqKeysMapAccumulator(keyMapper, valueMapper),
                                   uniqKeysMapMerger(),
                                   CH_ID);
    }

  • 第二个实现
 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> mapFactory) {
        BiConsumer<M, T> accumulator
                = (map, element) -> map.merge(keyMapper.apply(element),
                                              valueMapper.apply(element), mergeFunction);
        return new CollectorImpl<>(mapFactory, accumulator, mapMerger(mergeFunction), CH_ID);
    }

其中第一个实现,会在uniqKeysMapAccumulator(keyMapper, valueMapper)方法中通过Objects.requireNonNull(valueMapper.apply(element)) 控制value不能为null。

而第二个实现,最终会会调用Map.merge方法来合并value,这个方法里也会通过Objects.requireNonNull(value);来控制value不能为null。

解决方案

因此Collectors.toMap 方法是无法解决value为null 抛出异常的,但我们实现list转map的需求还是存在的,那么对于这类需求,可以选择另一种方式实现,就是用Collectors.groupingBy

实现方案 1

默认的Collectors.groupingBy 返回的是Map<Key,List<Value>> 形式的结果,但我们需要返回的Map<Key,Value>形式的结果。因此需要对需要做额外的一些处理。

先给出结果demo

    @Test
    public void test_groupByMap(){
        List<Data> dataList = List.of(
            new Data(1,"A"),
            new Data(2,"B"),
            new Data(3,"C"),
            new Data(4,null),
            new Data(5,null)
        );
        Map<Integer,String> dataMap = dataList.stream()
            .collect(Collectors.groupingBy(item->item.key,
                HashMap::new,
                Collectors.reducing(null,item->item.value,(v1,v2)->v2)
                )
            );

    }

原理就是利用额外的Collectors.reducing来做收集处理,将最终的List<Value> 转换成 Value

实现方案 2

学到另一种方案,调用Stream的另一个collect方法。

<R> R collect(Supplier<R> supplier,
                  BiConsumer<R, ? super T> accumulator,
                  BiConsumer<R, R> combiner);
public void test_toMap4(){
        List<Data> dataList = List.of(
            new Data(1,"A"),
            new Data(2,"B"),
            new Data(3,"C"),
            new Data(4,null),
            new Data(5,null)
        );
        Map<Integer,String> dataMap = dataList.stream()
            .collect(HashMap::new,(map,item)->map.put(item.key,item.value),(map1,map2)->map1.putAll(map2)
            );
    }

当然(map1,map2)->map1.putAll(map2) 也可以简化成HashMap::putAll

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-06-25 17:56:45  更:2022-06-25 18:00:47 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年1日历 -2025/1/31 10:44:58-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码