stream.flatmap可将用户→角色→权限的嵌套结构逐层展开为扁平的权限字符串列表,核心是将每个元素映射为stream后自动合并;需用空保护避免npe。

Stream.flatMap 可以将嵌套的权限结构(比如用户→角色→权限)一层层展开,最终得到一个扁平的权限字符串列表。关键在于用 flatMap 把每一层“集合转集合”的关系映射成“元素转流”,再逐级压平。
理解 flatMap 的核心作用
flatMap 不是简单遍历,而是对每个元素生成一个 Stream,然后自动把所有子 Stream 合并成一个整体流。它适合处理“一对多”关系的展开:
- map:把一个元素变成另一个元素(类型可变,但数量不变)
- flatMap:把一个元素变成零个、一个或多个元素的 Stream,最终汇总为单一流
典型层级结构示例
假设数据模型如下:
class User { String name; List<role> roles; }
class Role { String roleName; List<string> permissions; }
</string></role>
一个用户可能有多个角色,每个角色又包含若干权限字符串(如 "user:read", "order:write")。目标是从 List<user></user> 得到 List<string></string> 的全部权限去重后列表。
逐层 flatMap 实现扁平化
按层级顺序使用 flatMap,每一步解开一层嵌套:
- 第一步:用户 → 角色流 →
users.stream().flatMap(u -> u.roles.stream()) - 第二步:角色 → 权限流 →
.flatMap(r -> r.permissions.stream()) - 合并写法:
users.stream().flatMap(u -> u.roles.stream()).flatMap(r -> r.permissions.stream()).collect(Collectors.toList())
如果还需去重、过滤空值或转换格式,可在中间插入 filter(Objects::nonNull) 或 distinct() 等操作。
处理空集合与边界情况
实际中 roles 或 permissions 可能为 null 或空列表,直接调用 stream() 会 NPE 或无影响。稳妥做法:
- 在 flatMap 内部做空保护:
u.roles == null ? Stream.empty() : u.roles.stream() - 或统一用 Optional 处理:
Optional.ofNullable(u.roles).orElse(Collections.emptyList()).stream() - 避免在 permission 字符串上做 trim 或 toLowerCase 前未判空,导致 NullPointerException











