能否通过链式调用多个partitionBy一次性完成Person列表的双重分区?
分组Person列表的优化实现
问题描述
定义了如下Person记录:
public record Person(boolean male, int age) {}
需求是将一个List<Person>拆分为4个列表:18岁以上男性、18岁以下男性、18岁以上女性、18岁以下女性。当前实现代码如下:
Map<Boolean, List<Person>> peopleDividedBySex = people.stream() .collect(Collectors.partitioningBy(Person::male)); List<Person> males = peopleDividedBySex.get(Boolean.TRUE); List<Person> females = peopleDividedBySex.get(Boolean.FALSE); Map<Boolean, List<Person>> malesDividedByAge = males.stream() .collect(Collectors.partitioningBy(person -> person.age() > 18)); List<Person> malesOverEighteen = malesDividedByAge.get(Boolean.TRUE); List<Person> malesUnderEighteen = malesDividedByAge.get(Boolean.FALSE); Map<Boolean, List<Person>> femalesDividedByAge = males.stream() .collect(Collectors.partitioningBy(person -> person.age() > 18)); List<Person> femalesOverEighteen = femalesDividedByAge.get(Boolean.TRUE); List<Person> femalesUnderEighteen = femalesDividedByAge.get(Boolean.FALSE);
提问:是否可以通过链式调用多个partitionBy方法实现,避免创建多个流?
解答
完全可以通过**嵌套Collectors.partitioningBy**的方式,只用一次流操作完成分组,不需要多次创建流。
优化后的代码
// 一次流处理完成双层分区 Map<Boolean, Map<Boolean, List<Person>>> groupedPeople = people.stream() .collect(Collectors.partitioningBy( Person::male, // 第一层:按性别分区 Collectors.partitioningBy(p -> p.age() > 18) // 第二层:每个性别组内按年龄是否>18分区 )); // 取出四个目标列表 List<Person> malesOverEighteen = groupedPeople.get(true).get(true); List<Person> malesUnderEighteen = groupedPeople.get(true).get(false); List<Person> femalesOverEighteen = groupedPeople.get(false).get(true); List<Person> femalesUnderEighteen = groupedPeople.get(false).get(false);
说明
- 嵌套的
partitioningBy会先按外层条件(性别)将列表分成两组,再对每组应用内层的分区条件(年龄是否大于18),最终得到一个双层Map结构。 - 这种方式只遍历原列表一次,相比原实现的多次流操作,性能更优,代码也更简洁。
- 注意原代码存在一个bug:创建
femalesDividedByAge时误用了males.stream(),应该改为females.stream(),否则女性分组的结果会错误地使用男性数据。
内容的提问来源于stack exchange,提问作者Philippe Gioseffi
相关产品推荐
相关产品推荐

