如何用Java 8 Stream API重构多层嵌套循环的Map生成代码
Java 8 Stream重构多层循环提取SIM特征与OrderItem ID的Map实现
问题背景
需要将一段多层嵌套循环的代码用Java 8 Stream API重构,原代码功能是从IProductOrderDTO中提取名称为"SIM"的特征值作为Map的key,对应orderItem的ID作为Map的value。尝试编写的Stream代码无法同时获取这两个值,请求完善。
原循环代码
private Map<String,String> fetchAllSerialNumbers(IProductOrderDTO inputProductOrderDTO) { Map<String,String> serialNumbersFromToBeValidate = new HashMap<>(); // 注:原代码条件判断写反,应为CollectionUtils.isNotEmpty if (CollectionUtils.isNotEmpty(inputProductOrderDTO.getProductOrderItem())) { List<IProductOrderItemDTO> productOrderItems = inputProductOrderDTO.getProductOrderItem(); for (IProductOrderItemDTO productorder : productOrderItems) { for (IProductOrderItemDTO orderItem : productorder.getProductOrderItem()) { List<ICharacteristicDTO> characteristicList = orderItem.getProduct().getProductCharacteristic(); for(ICharacteristicDTO characteristic : characteristicList) { if("SIM".equals(characteristic.getName())) { serialNumbersFromToBeValidate.put(characteristic.getValue(),orderItem.getId()); } } } } } return serialNumbersFromToBeValidate; }
原代码条件判断
CollectionUtils.isEmpty逻辑错误,若不修正永远不会进入循环,重构时会同步修复。
未完成的Stream代码
private Map<String,String> fetchAllSerialNumbers(IProductOrderDTO inputProductOrderDTO) { Map<String,String> serialNumbersFromToBeValidate = inputProductOrderDTO.getProductOrderItem().stream(). flatMap(orderItem ->orderItem.getProductOrderItem().stream()). flatMap(ch -> ch.getProduct().getProductCharacteristic().stream()). filter(f->f.getName().equals("SIM")). map(ch->ch.getValue()). collect(Collectors.toMap(keyMapper, Function.identity())); // 无法同时获取特征值(key)和orderItem的ID(value) // 需要用map(ch->ch.getValue())作为key // 需要从flatMap(orderItem ->orderItem.getProductOrderItem().stream())中获取orderItem的ID作为value return serialNumbersFromToBeValidate; }
相关模型接口
public interface IProductOrderItemDTO extends Serializable { public List<IProductOrderItemDTO> getProductOrderItem(); public void setProductOrderItem(List<IProductOrderItemDTO> productOrderItem); public IProductRefOrValueDTO getProduct(); public void setProduct(IProductRefOrValueDTO product); // 补充:原接口缺失getId(),否则原循环代码无法运行 public String getId(); public void setId(String id); } public interface IProductRefOrValueDTO extends Serializable { public List<ICharacteristicDTO> getProductCharacteristic(); public void setProductCharacteristic(List<ICharacteristicDTO> productCharacteristic); } public interface ICharacteristicDTO extends Serializable { // 补充:原接口缺失必要getter,否则无法判断特征名称和取值 public String getName(); public void setName(String name); public String getValue(); public void setValue(String value); }
完善后的Stream实现
private Map<String, String> fetchAllSerialNumbers(IProductOrderDTO inputProductOrderDTO) { // 提前处理空列表,避免空指针 if (CollectionUtils.isEmpty(inputProductOrderDTO.getProductOrderItem())) { return Collections.emptyMap(); } return inputProductOrderDTO.getProductOrderItem().stream() // 展开外层orderItem的子orderItem列表 .flatMap(outerItem -> outerItem.getProductOrderItem().stream()) // 绑定orderItem与它的特征列表,保留上下文引用 .flatMap(orderItem -> orderItem.getProduct().getProductCharacteristic().stream() .map(characteristic -> new AbstractMap.SimpleEntry<>(characteristic, orderItem)) ) // 过滤出SIM特征 .filter(entry -> "SIM".equals(entry.getKey().getName())) // 收集为目标Map,处理重复key场景 .collect(Collectors.toMap( entry -> entry.getKey().getValue(), entry -> entry.getValue().getId(), // 重复key时保留第一个值,可根据业务调整策略 (existing, replacement) -> existing )); }
关键说明
- 上下文绑定:通过
AbstractMap.SimpleEntry将特征与对应的orderItem绑定,解决Stream操作中丢失orderItem引用的问题,确保能同时获取特征值和orderItem ID。 - 空值防护:开头直接判断外层列表是否为空,返回空Map避免后续Stream操作抛出空指针异常。
- 冲突处理:
Collectors.toMap的第三个参数用于处理重复key的冲突,这里选择保留第一个出现的值,可根据业务需求改为抛出异常或保留最新值。
内容的提问来源于stack exchange,提问作者Vaibs
相关产品推荐
相关产品推荐

