Java Stream API聚合嵌套列表时返回List<List<C3>>而非List<C3>的问题
问题根因
map操作的语义理解偏差:map是一对一元素转换,每次转换都会保留原有的嵌套结构。你两次调用map时,第一次把每个C1对象转成了它内部的c2list,此时流的类型已经从Stream<C1>变成了Stream<List<C2>>;第二次再把每个List<C2>转成对应的c3list,流类型进一步变成Stream<List<C3>>,最终经过collect收集出来自然是嵌套的List<List<C3>>,完全没有执行摊平聚合的动作。- 基础语法错误:Java中集合获取串行流需要调用
stream()方法,你写的list.stream是直接访问属性的写法,当前代码根本无法通过编译。 - 空指针隐患:如果任意
C1实例的c2list为null,或任意C2实例的c3list为null,直接访问属性会直接抛出空指针异常,无法稳定跑完聚合流程。
修正实现
需要用flatMap替换两次转换里的map操作:flatMap的作用是将每个元素转换出的子流直接合并到主流程中,完全消除列表嵌套的层级。
核心修正代码:
public List<C3> getAllC3(List<C1> list) { return list.stream() .flatMap(a -> a.c2list.stream()) .flatMap(b -> b.c3list.stream()) .collect(Collectors.toList()); }
如果需要规避空指针,可以对可能为null的列表做空值兜底,替换为空流避免抛错:
public List<C3> getAllC3WithNullSafe(List<C1> list) { return list.stream() .flatMap(a -> Optional.ofNullable(a.c2list).stream().flatMap(List::stream)) .flatMap(b -> Optional.ofNullable(b.c3list).stream().flatMap(List::stream)) .collect(Collectors.toList()); }
最终的执行逻辑是逐层拆解嵌套结构:遍历入参列表里的所有C1,取出每个C1携带的全部C2,再遍历这些C2取出每个对象携带的全部C3,最终把所有散落在各层级的C3聚合到同一个List
内容的提问来源于stack exchange,提问作者Facundo Laxalde
相关产品推荐
相关产品推荐

