如何用Java Streams按内部集合元素分组:将List<Shop>转为Map<Supplier, List<Shop>>
使用Java Streams实现从
List<Shop>到Map<Supplier, List<Shop>>的转换 这是个典型的分组映射需求,核心思路是先扁平化每个店铺的供应商列表,再按供应商分组,我来一步步给你讲清楚实现细节:
1. 关键前提:重写Supplier的equals和hashCode
因为Supplier要作为Map的key,必须正确实现equals()和hashCode()方法——默认的对象引用比较会导致逻辑上完全相同的Supplier被当成不同的key,分组结果会出错。示例实现如下:
import java.util.Objects; class Supplier { private Long id; private String supplierName; // 构造器、getter、setter方法省略 @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Supplier supplier = (Supplier) o; return Objects.equals(id, supplier.id) && Objects.equals(supplierName, supplier.supplierName); } @Override public int hashCode() { return Objects.hash(id, supplierName); } }
2. Streams完整实现代码
import java.util.List; import java.util.Map; import java.util.AbstractMap; import java.util.stream.Collectors; import java.util.Objects; // 假设你已经初始化好了shops列表 List<Shop> shops = ...; Map<Supplier, List<Shop>> supplierShopsMap = shops.stream() // 过滤掉供应商列表为null的店铺,避免空指针异常 .filter(shop -> shop.getSuppliers() != null) // 扁平化处理:把每个店铺拆成「供应商-店铺」的键值对 .flatMap(shop -> shop.getSuppliers().stream() // 可选:过滤掉null的供应商,让结果更干净 .filter(Objects::nonNull) .map(supplier -> new AbstractMap.SimpleEntry<>(supplier, shop))) // 按供应商分组,收集对应的店铺列表 .collect(Collectors.groupingBy( AbstractMap.SimpleEntry::getKey, Collectors.mapping(AbstractMap.SimpleEntry::getValue, Collectors.toList()) ));
3. 代码分步解释
filter(shop -> shop.getSuppliers() != null):提前过滤掉供应商列表为null的店铺,防止后续调用stream()时抛出NPE。flatMap(...):这是核心步骤,把单个Shop转换成多个(Supplier, Shop)键值对,让每个供应商都能和它所属的店铺建立关联。这里用AbstractMap.SimpleEntry临时存储键值对,不需要额外自定义类。Collectors.groupingBy(...):- 第一个参数指定分组依据是
Supplier(键值对中的key); - 第二个参数负责把键值对中的
Shop收集成列表,作为对应Supplier的value。
- 第一个参数指定分组依据是
可选优化
如果你的业务场景中不存在null的供应商或店铺,可以去掉对应的filter步骤,但保留null检查会让代码更健壮。
内容的提问来源于stack exchange,提问作者antongarakh
相关产品推荐
相关产品推荐

