Java Streams:基于两个字段对列表进行分组
嘿,这个问题问得很精准!咱们分两种场景来拆解,用Java Streams轻松实现分组需求~
场景1:一个ContactNumber仅关联一个Owner
这种情况下,ContactNumber和Owner是一一对应的关系,所以我们可以用复合键来同时把两者作为分组依据。Java里有几种实现复合键的方式,推荐用Java 16+的Record(简洁且自动实现equals/hashCode),或者用AbstractMap.SimpleEntry兼容旧版本。
示例代码(用Record做复合键)
首先定义一个记录类作为分组键:
// Java 16+ 可用,自动实现equals、hashCode和toString record OwnerContactKey(Owner owner, ContactNumber contactNumber) {}
然后执行分组:
List<Car> cars = ...; // 你的汽车列表 Map<OwnerContactKey, List<Car>> groupedCars = cars.stream() .collect(Collectors.groupingBy(car -> new OwnerContactKey(car.getOwner(), car.getOwner().getContactNumber()) ));
兼容旧版本的方式(用SimpleEntry)
如果你的项目还在使用Java 16以下,可以用AbstractMap.SimpleEntry:
Map<Map.Entry<Owner, ContactNumber>, List<Car>> groupedCars = cars.stream() .collect(Collectors.groupingBy(car -> new AbstractMap.SimpleEntry<>(car.getOwner(), car.getOwner().getContactNumber()) ));
因为ContactNumber和Owner一一对应,所以每个复合键都是唯一的,分组结果里每个键对应的车辆列表就是该Owner(及其关联ContactNumber)的所有汽车。
场景2:一个ContactNumber可关联多个Owner
这种场景下,ContactNumber是一对多的关联(同一个号码属于多个车主),最清晰的实现方式是嵌套分组——先按ContactNumber分组,再在每个号码下按Owner分组,这样能直观看到每个联系方式对应的所有车主及其车辆。
示例代码(嵌套分组)
List<Car> cars = ...; // 你的汽车列表 // 第一层键:ContactNumber,第二层键:Owner,值是对应Owner的车辆列表 Map<ContactNumber, Map<Owner, List<Car>>> groupedCars = cars.stream() .collect(Collectors.groupingBy( // 第一层分组:按ContactNumber car -> car.getOwner().getContactNumber(), // 第二层分组:在每个ContactNumber下按Owner分组 Collectors.groupingBy(Car::getOwner) ));
可选:用复合键直接分组
如果你不需要分层查看,只是想直接按「ContactNumber + Owner」的组合作为唯一键分组,也可以用场景1里的复合键方式:
record ContactOwnerKey(ContactNumber contactNumber, Owner owner) {} Map<ContactOwnerKey, List<Car>> groupedCars = cars.stream() .collect(Collectors.groupingBy(car -> new ContactOwnerKey(car.getOwner().getContactNumber(), car.getOwner()) ));
不过这种方式的缺点是,如果你想查询某个ContactNumber下的所有车主,需要遍历所有键进行筛选,而嵌套分组可以直接通过groupedCars.get(contactNumber)拿到该号码对应的所有Owner和车辆,可读性和实用性更强。
内容的提问来源于stack exchange,提问作者Eduardo
相关产品推荐
相关产品推荐

