Java 8 Streams三级以上分组:生成指定嵌套Map结构
用Java 8 Stream实现指定嵌套Map结构
需求回顾
需要将包含编码类型、新旧长短编码的对象列表,转换成如下嵌套结构的Map(对应示例JSON):
外层以account为键,内层按codetype分组,每个编码类型下包含OLD和NEW两个节点,分别存储对应长短编码。
原代码问题分析
你提供的代码存在以下核心问题:
- 仅处理了
OLD节点,未生成NEW节点,无法满足完整结构需求 - 使用
groupingBy配合toList,导致最终结构包含列表,但目标结构中每个OLD/NEW是单个对象而非列表 - 泛型定义与目标结构不匹配,引入了不必要的
List<Object>层级
正确实现方案
方案1:自定义类型实现(类型安全)
先定义对应结构的实体类,再通过Stream的toMap完成转换:
// 假设已有实体类GetCodeTypes(包含对应getter方法) class GetCodeTypes { private String codetype; private String shortOldCode; private String longOldCode; private String shortNewCode; private String longNewCode; // getter方法 public String getCodetype() { return codetype; } public String getShortOldCode() { return shortOldCode; } public String getLongOldCode() { return longOldCode; } public String getShortNewCode() { return shortNewCode; } public String getLongNewCode() { return longNewCode; } } // 定义长短编码对的实体类 class CodePair { private String shortCode; private String longCode; public CodePair(String shortCode, String longCode) { this.shortCode = shortCode; this.longCode = longCode; } // getter方法(序列化需要) public String getShort() { return shortCode; } public String getLong() { return longCode; } } // 定义单个编码类型的OLD/NEW结构 class CodeTypeEntry { private CodePair OLD; private CodePair NEW; public CodeTypeEntry(CodePair oldPair, CodePair newPair) { this.OLD = oldPair; this.NEW = newPair; } public CodePair getOLD() { return OLD; } public CodePair getNEW() { return NEW; } }
核心转换代码:
List<GetCodeTypes> dataMap = // 你的对象列表 // 按codetype分组,生成每个编码类型对应的OLD/NEW结构 Map<String, CodeTypeEntry> codeTypeMap = dataMap.stream() .collect(Collectors.toMap( GetCodeTypes::getCodetype, code -> { CodePair oldPair = new CodePair(code.getShortOldCode(), code.getLongOldCode()); CodePair newPair = new CodePair(code.getShortNewCode(), code.getLongNewCode()); return new CodeTypeEntry(oldPair, newPair); }, // 处理重复codetype的情况,这里保留已有值,可根据需求调整 (existing, replacement) -> existing )); // 包装到外层account键下 Map<String, Map<String, CodeTypeEntry>> finalResult = new HashMap<>(); finalResult.put("account", codeTypeMap);
方案2:纯Map嵌套实现(无需自定义类)
如果不想新增实体类,可直接用嵌套Map完成转换:
List<GetCodeTypes> dataMap = // 你的对象列表 Map<String, Map<String, Map<String, Map<String, String>>>> finalResult = new HashMap<>(); Map<String, Map<String, Map<String, String>>> codeTypeMap = dataMap.stream() .collect(Collectors.toMap( GetCodeTypes::getCodetype, code -> { // 构建OLD节点 Map<String, String> oldMap = new HashMap<>(); oldMap.put("short", code.getShortOldCode()); oldMap.put("long", code.getLongOldCode()); // 构建NEW节点 Map<String, String> newMap = new HashMap<>(); newMap.put("short", code.getShortNewCode()); newMap.put("long", code.getLongNewCode()); // 组装OLD/NEW到当前编码类型节点 Map<String, Map<String, String>> oldNewMap = new HashMap<>(); oldNewMap.put("OLD", oldMap); oldNewMap.put("NEW", newMap); return oldNewMap; }, (existing, replacement) -> existing )); finalResult.put("account", codeTypeMap);
关键思路说明
- 使用
Collectors.toMap而非groupingBy:因为每个codetype对应唯一的一组OLD/NEW数据,toMap更适合这种键值一一对应的场景 - 一次性完成单个对象到OLD/NEW结构的转换:在
toMap的value生成器中直接构建目标结构,避免多层嵌套收集器的复杂逻辑
内容的提问来源于stack exchange,提问作者CodeFromSverige
相关产品推荐
相关产品推荐

