如何将List<Person>转换为Map<String, Map<LocalDate,List<Person>>>?
用Java 8 Stream API实现双层分组
这问题太常见了!刚好可以用Java 8引入的Stream API结合Collectors.groupingBy来完成双层分组,代码简洁又高效。
核心实现代码
直接上最简洁的解决方案,一行流操作就能搞定:
// 假设你已经有了Person集合 List<Person> personList = getYourPersonList(); Map<String, Map<LocalDate, List<Person>>> groupedMap = personList.stream() // 第一层按personId分组,第二层按date分组 .collect(Collectors.groupingBy( Person::getPersonId, // 外层Map的键:personId Collectors.groupingBy(Person::getDate) // 内层Map的键:date,值是对应日期的Person列表 ));
代码解释
- 第一个
Collectors.groupingBy(Person::getPersonId):先把整个List按personId拆分,得到一个Map<String, List<Person>>,每个键是唯一的personId,对应的值是该id下所有Person对象的集合。 - 第二个
groupingBy作为下游收集器,把每个personId分组里的List再按 date做二次分组,最终就得到了你需要的Map<String, Map<LocalDate, List<Person>>>结构。
进阶:处理空值与自定义排序
如果你的业务场景中存在personId或date为null的情况,建议先过滤掉这些无效数据,避免空指针异常:
Map<String, Map<LocalDate, List<Person>>> groupedMap = personList.stream() // 过滤掉personId或date为空的对象 .filter(p -> p.getPersonId() != null && p.getDate() != null) .collect(Collectors.groupingBy( Person::getPersonId, Collectors.groupingBy(Person::getDate) ));
要是还想对每个日期分组里的Person列表做排序(比如按type字段排序),可以在第二层分组里再加一个收集器:
Map<String, Map<LocalDate, List<Person>>> groupedMap = personList.stream() .collect(Collectors.groupingBy( Person::getPersonId, Collectors.groupingBy( Person::getDate, // 先收集成List,再按type排序 Collectors.collectingAndThen( Collectors.toList(), list -> list.stream().sorted(Comparator.comparing(Person::getType)).collect(Collectors.toList()) ) ) ));
内容的提问来源于stack exchange,提问作者Ram
相关产品推荐
相关产品推荐

