使用Collectors.toMap去重合并时触发NullPointerException问题
问题:创建ProductKey到ProductDetail的Map时触发NullPointerException
我正尝试为需要添加ProductDetail的Products列表创建一个Map<ProductKey, ProductDetail>。ProductDetail对象通过ProductDetailLookUpService从数据库读取(因涉及内部信息未展示该服务)。产品可能存在或不存在ProductDetail,同类产品可能共享同一ProductDetail。但在执行合并操作时触发了NullPointerException。
相关类定义
@Data static class ProductKey{ @EqualsAndHashCode.Include private Long productCode; @EqualsAndHashCode.Include private Long productDetailCode; } @Data class Product { @EqualsAndHashCode.Include private ProductKey productKey; @EqualsAndHashCode.Include private ProductDetail productDetail; } @Data class ProductDetail{ @EqualsAndHashCode.Include private Long productCode; private String description; private BigDecimal price; private String category; } public static Optional<ProductKey> findProductKey(Long productCode, List<ProductKey> productKeys) { return productKeys.stream() .filter(productKey -> productCode.equals(productKey.getProductCode())) .takeWhile(productKey -> productKey != null) .findFirst(); }
报错信息
java.lang.NullPointerException: null at java.base/java.util.HashMap.merge(HashMap.java:1267) ~[na:na] at java.base/java.util.stream.Collectors.lambda$toMap$68(Collectors.java:1658) ~[na:na] at java.base/java.util.stream.ReduceOps$3ReducingSink.accept(ReduceOps.java:169) ~[na:na] at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:177) ~[na:na] at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195) ~[na:na] at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:177) ~[na:na]
填充Map的代码(已修改但仍报错)
我原本添加了过滤器,确保productDetailMap包含匹配的productKey.getProductCode(),以为能排除无匹配productCode的产品,合并时不会出现null,但实际仍报错:
List<ProductKey> productKeyList = // 初始化列表 Map<Long, ProductDetail> productDetailMap = // 初始化map Map<ProductKey, ProductDetail> prodDetailByKey = productKeyList.stream() .map(productKey -> findProductKey(productKey.getProductCode(), productKeyList)) .filter(Optional::isPresent) .map(Optional::get) .filter(productKey -> productDetailMap.values().contains(productKey.getProductCode())) .collect(Collectors.toMap( Function.identity(), productKey -> productDetailMap.get(productKey.getProductCode()), (left, right) -> left // 预防productKeyList中出现重复元素 ));
补充操作建议
- 将Map中的ProductDetail设置到对应Product时,使用
Iterable.forEach()比stream更合适:
List<Product> products = service.readProducts(); products.forEach(product -> product.setProductDetail(prodDetailByKey.get(product.getProductKey())) );
- 移除Map中的null值可使用以下方式:
productDetailMap.values().removeIf(Objects::isNull);
内容的提问来源于stack exchange,提问作者BreenDeen
相关产品推荐
相关产品推荐

