如何使用Java Stream替代多层嵌套foreach实现集合过滤逻辑
基于Java Stream API的代码重构方案
完全可以用Stream API替换现有多层嵌套for循环写法,重构后的代码逻辑和原有实现100%一致,且结构更扁平、可读性更强,同时保留原代码短路遍历的性能优势,不会产生额外的全量遍历开销。
1. 重构特征过滤方法filterByCharacteristcs
原方法三层嵌套循环的逻辑可以通过flatMap拍平嵌套集合,配合anyMatch实现短路匹配,代码如下:
private boolean filterByCharacteristcs(final RuntimeProductOfferEntity offer, final String duration) { return offer.getTemplates().stream() // 拍平模板下的所有特征集合 .flatMap(template -> template.getCharacteristics().stream()) // 筛选编码为VARIJACIJA的特征(忽略大小写) .filter(ch -> "VARIJACIJA".equalsIgnoreCase(ch.getCode())) // 拍平特征下的所有特征值集合 .flatMap(ch -> ch.getCharacteristicValues().stream()) // 任意一个特征值和目标duration匹配(忽略大小写)就返回true,短路终止遍历 .anyMatch(value -> duration.equalsIgnoreCase(value.getValue())); }
说明:重构后方法返回基本类型boolean,不存在null返回的可能,不需要再额外用Boolean.TRUE.equals()做非空判断,减少不必要的装箱拆箱开销;anyMatch是短路操作,找到第一个匹配项后会立刻终止后续遍历,和原方法中提前return的执行逻辑、性能完全一致。
2. 重构主集合遍历组装逻辑
原遍历eligibleOffers筛选、组装响应对象的逻辑,可以直接通过Stream的filter、map、collect操作实现:
// Java 16及以上版本可以直接用toList()收集结果,低版本替换为Collectors.toList()即可 List<ProductOfferResponse> productOffers = eligibleOffers.stream() // 筛选销售子分类匹配的商品(忽略大小写) .filter(offer -> offer.getSalesSubCategory().equalsIgnoreCase(nonBillable.getSubCategory())) // 筛选特征规则匹配的商品 .filter(offer -> filterByCharacteristcs(offer, nonBillable.getDuration().toString())) // 组装响应对象 .map(offer -> ProductOfferResponse.builder() .categoryId(nonBillable.getCategoryId()) .offerCode(offer.getCode()) .build()) .toList();
注意事项
- 所有字符串比较的大小写规则、判断逻辑和原代码完全对齐,没有业务逻辑改动
- 如果业务场景下关联集合(templates、characteristics、characteristicValues)可能为null,可以在flatMap前加一层非空判断(比如用
Optional.ofNullable包裹集合取stream,避免空指针),如果需要和原代码集合为null时抛空指针的行为保持一致,则不需要额外处理 - 如果觉得单独抽过滤方法冗余,也可以把特征匹配的逻辑直接内联到主流程的filter中,但单独抽取方法的可维护性更好,后续调整特征匹配规则时不需要改动主流程代码
内容的提问来源于stack exchange,提问作者None
相关产品推荐
相关产品推荐

