线上问题:Stream toMap value为null时抛空指针

1 问题复现

使用stream的toMap方法从List<对象A>转Map<String, String>,
当对象A中的属性值为null的属性转换为Map的value时,使用toMap会抛出异常。
即:
对象:UserEntity属性nickname值为null,将nickname作为Map的value,uid作为key,抛异常的代码片段如下:

List<UserEntity> userEntityList1 = new ArrayList<>();
        userEntityList1.add(new UserEntity("1", null, "male"));
        Map<String, String> map1 = new HashMap<>();
        map1 = Optional.ofNullable(userEntityList1).orElse(new ArrayList<>()).stream().collect(Collectors.toMap(UserEntity::getUid, UserEntity::getNickname, (oldVal, newVal) -> oldVal));
  • 测试样例
package lambda_expression;

import common.entity.BaseUserEntity;
import common.entity.UserAgeEntity;
import common.entity.UserEntity;

import java.util.*;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * Stream数据转换测试.
 *
 * @author xindaqi
 * @date 2021-06-28 17:20
 */
public class DataTransformStreamTest {

    private static final Logger logger = Logger.getLogger("StreamTest");

    public static void main(String[] args) {

        List<UserEntity> userEntityList1 = new ArrayList<>();
        userEntityList1.add(new UserEntity("1", null, "male"));
        Map<String, String> map1 = new HashMap<>();
        map1 = Optional.ofNullable(userEntityList1).orElse(new ArrayList<>()).stream().collect(Collectors.toMap(UserEntity::getUid, UserEntity::getNickname, (oldVal, newVal) -> oldVal));
        logger.info("map1:" + map1);
        if(null != map1.get("1")) {
            logger.info("map1 not empty");
        } else {
            logger.info("map1 is empty");
        }
    }
}
  • 异常
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:1384)
	at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482)
	at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472)
	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 lambda_expression.DataTransformStreamTest.main(DataTransformStreamTest.java:176)

2 原因

toMap源码:

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);
    }
    
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);
        
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;
    }
  • 分析
    由源码可知,toMap的中调用的merge方法中对象要求:Objects.requireNonNull(value);可知,Map的value不可为null,因此,使用toMap方式转换Map时,值value不能为null。

3 方案

使用collect(HashMap::new…)方案,避免值为null抛空指针。

map1 = Optional.ofNullable(userEntityList1).orElse(new ArrayList<>()).stream().collect(HashMap::new, (k, v) -> k.put(v.getUid(), v.getNickname()), HashMap::putAll);

4 附

当key为null时,使用toMap不会抛空指针。

  • 7
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天然玩家

坚持才能做到极致

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值