使用Java Stream groupingBy分组后如何对分组实体进行二次聚合
实现方案
方案1:一步直接分组(推荐,性能更好)
不需要先按首字母拆分再合并,直接在分组时判断姓氏首字母所属区间即可,代码如下:
import java.util.List; import java.util.Map; import java.util.stream.Collectors; // 核心逻辑 Map<String, List<Person>> result = myList.stream() .collect(Collectors.groupingBy(person -> { // 先转大写避免大小写判断异常 char firstLetter = Character.toUpperCase(person.getLastName().charAt(0)); if (firstLetter >= 'A' && firstLetter <= 'H') { return "A-H"; } else if (firstLetter >= 'I' && firstLetter <= 'N') { return "I-N"; } else if (firstLetter >= 'O' && firstLetter <= 'Z') { return "O-Z"; } // 异常字符可自定义分类,这里默认归为其他,可根据需求调整 return "其他"; })); // 打印验证 result.forEach((k, v) -> System.out.println(k + " = " + v));
方案2:在现有首字母分组基础上二次聚合
如果你确实需要先按首字母分组再合并,也可以对首字母分组的结果做二次收集:
Map<String, List<Person>> result = myList.stream() // 第一步:按首字母分组,和现有逻辑一致 .collect(Collectors.groupingBy(p -> String.valueOf(Character.toUpperCase(p.getLastName().charAt(0))))) .entrySet() .stream() // 第二步:按首字母所属区间合并分组 .collect(Collectors.groupingBy( entry -> { char first = entry.getKey().charAt(0); if (first <= 'H') return "A-H"; else if (first <= 'N') return "I-N"; else return "O-Z"; }, // 把同区间的所有Person列表合并成一个列表 Collectors.flatMapping(entry -> entry.getValue().stream(), Collectors.toList()) ));
如果使用Java 8,没有Collectors.flatMapping方法,可以改用遍历合并列表的方式实现。
输出结果
两种方案的输出都和期望效果一致:
A-H = [Person{Helena, Graves}, Person{Aysha, Graham}, Person{Melissa, Carpenter}, Person{Marie, Daniel}, Person{Robin, French}, Person{Annie, Bradley}] I-N = [Person{Jasmine, Knight}, Person{Madeleine, Jenkins}, Person{Christina, Johnson}, Person{Freya, Montgomery}] O-Z = [Person{Phoebe, Reyes}, Person{Tamara, Wyatt}, Person{Lacey, Todd}, Person{Heather, Parker}, Person{Lauren, Wright}]
内容的提问来源于stack exchange,提问作者wannaBeDev
相关产品推荐
相关产品推荐

