Java处理多级映射需用Stream嵌套分组或手动构建,常用Collectors.groupingBy嵌套实现层级分组,注意空值防护;也可用toMap配合合并逻辑,或封装实体方法提升可读性与安全性。
Java 中处理多级映射,核心在于利用 Stream 的嵌套分组或嵌套映射能力,而不是靠单个方法引用“一步到位”。多级映射本质是层级结构的构建,常见于按国家→省份→城市、订单→商品→SKU 等场景。直接写 person::getAddress().getCity() 会编译失败,必须用合法且可读的方式组织逻辑。
这是最常用、语义最清晰的方式。每级分组对应一个 groupingBy,内层作为外层的下游收集器。
示例代码:
Map<String, Map<String, List<String>>> regionTree = list.stream() .collect(Collectors.groupingBy( Country::getPname, // 一级:省份 Collectors.groupingBy( Country::getCname, // 二级:城市 Collectors.mapping(Country::getDname, Collectors.toList()) // 三级:地区列表 ) ));
注意:中间层级不能为 null,否则运行时抛 NullPointerException;建议在数据源或 map 前做空值过滤或默认值处理。
立即学习“Java免费学习笔记(深入)”;
当需要精确控制键类型、避免重复键冲突,或最终结构是 Map<k1 map v>></k1> 而非分组统计时,更适合用 toMap + 手动合并逻辑。
pid)收集,value 是一个 Map
Map
Collectors.toMap 配合 merge 函数处理键冲突示例(简化版):
Map<Integer, Map<Integer, String>> pidToCidName = list.stream() .collect(Collectors.toMap( Country::getPid, c -> Collections.singletonMap(c.getCid(), c.getCname()), (m1, m2) -> { Map<Integer, String> merged = new HashMap<>(m1); merged.putAll(m2); return merged; } ));
若多级属性访问频繁(如 user.getProfile().getAddress().getCity()),硬写 lambda 易出错且重复。推荐在实体类中封装方法:
User 类里加 getCity() 方法,内部判空并链式调用User::getCity,和单级属性一样简洁例如:
public String getCity() { return profile != null && profile.getAddress() != null ? profile.getAddress().getCity() : null;}// 后续可直接:List<String> cities = users.stream().map(User::getCity).collect(Collectors.toList());
面对 List<Map<String, Object>> 这类松散结构,Lambda 映射需手动解包,不能依赖方法引用。
m -> (String)((Map)m.get("address")).get("city")
Optional.ofNullable 链式调用例如:
List<String> cities = data.stream() .map(item -> Optional.ofNullable((Map<?, ?>) item.get("address")) .map(addr -> (String) addr.get("city")) .orElse(null)) .collect(Collectors.toList());