背景
交易状态为失败的售后退款记录需要返回失败原因,失败原因存在另一张扣款流水表里面,写了一个私有方法用于填充失败原因,其中用到了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())));
}