Java 8 Stream groupingBy疑问:如何按City对象而非邮编字符串分组
嘿,这个问题我之前做项目的时候也碰到过,太懂这种纠结的感觉了!咱们来一步步解决它:
问题根源
你直接用Collectors.groupingBy(Person::getCity)失效,本质原因是Java默认的equals()和hashCode()方法是基于对象引用的——哪怕两个City对象的postalcode完全一样,只要它们是不同的实例,就会被groupingBy当成不同的分组key,自然达不到按邮编分组的效果。
而用person -> person.city.postalcode分组,得到的是Map<String, List<Person>>,这是因为key变成了字符串类型的邮编,不是你想要的City对象。
解决方案1:给City类重写equals()和hashCode()(推荐)
如果业务上postalcode是City的唯一标识(或者你希望只要邮编相同就归为同一组),那直接给City类重写这两个方法,让它们只基于postalcode判断相等:
import java.util.Objects; public class City { private String postalcode; // 其他字段(比如cityName等) // 重写equals,只比较postalcode @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; City city = (City) o; return Objects.equals(postalcode, city.postalcode); } // 重写hashCode,基于postalcode生成哈希值 @Override public int hashCode() { return Objects.hash(postalcode); } // getter、setter等方法 }
重写之后,直接用City对象分组就可以得到你想要的结果:
Map<City, List<Person>> groupedByCity = personList.stream() .collect(Collectors.groupingBy(Person::getCity));
现在只要两个City的邮编相同,就会被groupingBy识别为同一个key,对应的Person会被分到同一组里。
解决方案2:不修改City类的情况下转换Map
如果因为某些原因不能修改City类(比如它是第三方库的类,或者其他业务逻辑依赖原有的引用相等判断),那可以先按邮编分组,再把结果转换成Map<City, List<Person>>:
Map<City, List<Person>> groupedByCity = personList.stream() // 先按邮编分组得到Map<String, List<Person>> .collect(Collectors.groupingBy(p -> p.getCity().getPostalcode())) // 把每个entry的key转换成City对象(这里取每组第一个Person的City作为key) .entrySet().stream() .collect(Collectors.toMap( entry -> entry.getValue().get(0).getCity(), Map.Entry::getValue ));
⚠️ 注意:这种方法要确保同一邮编对应的City对象在其他字段上是一致的,否则如果同一邮编下的City有不同的名称或其他属性,取第一个City作为key可能不符合你的预期。
内容的提问来源于stack exchange,提问作者Paolo
相关产品推荐
相关产品推荐

