Stream使用Collectors.toMap方法当value为NULL时抛NullPointException

这篇博客讲述了在Java应用中遇到HashMap异常的情况,具体是由于使用Collectors.toMap方法时,遇到了NullPointerException。问题源于HashMap不允许value值为null,而填充失败原因时从DeductionFlowDTO获取的remark字段可能存在null值。为了解决这个问题,作者检查了异常日志,并修改了代码,当remark为null时,将其替换为空字符串,从而避免了异常的发生。这个解决方案确保了数据处理的稳定性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

背景

交易状态为失败的售后退款记录需要返回失败原因,失败原因存在另一张扣款流水表里面,写了一个私有方法用于填充失败原因,其中用到了Collectors.toMap方法用于将List转换成Map。

/**
     * 为交易失败的记录填充失败原因
     * @param items 列表
     */
    private void fillRemark(List<AfterSaleRefundBusinessRecordDTO> items) {
        List<String> flowNos = items.stream().filter(item -> Objects.equals(item.getRefundResult(), AfterSaleEnum.RefundFlowResultEnum.TRANSACTION_FAIL.getCode()))
                .map(AfterSaleRefundBusinessRecordDTO::getFlowNo).distinct().collect(Collectors.toList());
        if (CollectionUtils.isEmpty(flowNos)) {
            return;
        }

				Map<String, String> remarkMap = deductionFlowCoreService.selectByFlowNos(flowNos).stream().collect(Collectors.toMap(DeductionFlowDTO::getFlowNo,
				                DeductionFlowDTO::getRemark));
        items.stream().filter(item -> Objects.equals(item.getRefundResult(), AfterSaleEnum.RefundFlowResultEnum.TRANSACTION_FAIL.getCode()))
                .forEach(item -> item.setRemark(remarkMap.get(item.getFlowNo())));
    }

排查

查看异常日志发现是HashMap里面抛出的异常

java.lang.NullPointerException: null
	at java.util.HashMap.merge(HashMap.java:1216) ~[?:1.8.0_73]
	at java.util.stream.Collectors.lambda$toMap$172(Collectors.java:1320) ~[?:1.8.0_73]
	at java.util.stream.ReduceOps$3ReducingSink.accept(ReduceOps.java:169) ~[?:1.8.0_73]
	at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1374) ~[?:1.8.0_73]
	at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481) ~[?:1.8.0_73]
	at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471) ~[?:1.8.0_73]
	at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708) ~[?:1.8.0_73]
	at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[?:1.8.0_73]
	at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499) ~[?:1.8.0_73]
	at com.yihuan.easychange.sale.biz.sales.module.aftersale.core.impl.AfterSaleRefundBusinessRecordCoreServiceImpl.fillRemark(AfterSaleRefundBusinessRecordCoreServiceImpl.java:74) ~[classes/:?]

查看HashMap.merge的代码,发现该方法不允许value值为null,而value的值就是来源于DeductionFlowDTO::getRemark

		@Override
    public V merge(K key, V value,
                   BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
        if (value == null)
            throw new NullPointerException();
        if (remappingFunction == null)
            throw new NullPointerException();
        int hash = hash(key);
        Node<K,V>[] tab; Node<K,V> first; int n, i;
        int binCount = 0;
        TreeNode<K,V> t = null;
        Node<K,V> old = null;
        if (size > threshold || (tab = table) == null ||
            (n = tab.length) == 0)
            n = (tab = resize()).length;
        if ((first = tab[i = (n - 1) & hash]) != null) {
......

解决方案

当remark为null时,将其替换为空字符串

/**
     * 为交易失败的记录填充失败原因
     * @param items 列表
     */
    private void fillRemark(List<AfterSaleRefundBusinessRecordDTO> items) {
        List<String> flowNos = items.stream().filter(item -> Objects.equals(item.getRefundResult(), AfterSaleEnum.RefundFlowResultEnum.TRANSACTION_FAIL.getCode()))
                .map(AfterSaleRefundBusinessRecordDTO::getFlowNo).distinct().collect(Collectors.toList());
        if (CollectionUtils.isEmpty(flowNos)) {
            return;
        }

        Map<String, String> remarkMap = deductionFlowCoreService.selectByFlowNos(flowNos).stream().collect(Collectors.toMap(DeductionFlowDTO::getFlowNo,
                value -> Optional.ofNullable(value.getRemark()).orElse("")
        ));
        items.stream().filter(item -> Objects.equals(item.getRefundResult(), AfterSaleEnum.RefundFlowResultEnum.TRANSACTION_FAIL.getCode()))
                .forEach(item -> item.setRemark(remarkMap.get(item.getFlowNo())));
    }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值