如何更优雅地过滤嵌套对象列表中的指定General实例?
问题描述
我有一个GpbCodesAndVersions类型的列表,定义如下:
List<GpbCodesAndVersions> lst = Arrays.asList( new GpbCodesAndVersions("code1", 1, Arrays.asList(new General(1), new General(2))), new GpbCodesAndVersions("code2", 2, Arrays.asList(new General(1), new General(5))), new GpbCodesAndVersions("code3", 3, Arrays.asList(new General(2), new General(3))), new GpbCodesAndVersions("code4", 4, Arrays.asList(new General(2), new General(4))) );
我需要对这个列表做过滤,最终得到仅包含General(status=1)元素的GpbCodesAndVersions列表,预期结果是:
GpbCodesAndVersions(code=code1, version=1, content=[General(status=1)]), GpbCodesAndVersions(code=code2, version=2, content=[General(status=1)])
我自己写的代码能实现需求,但想知道有没有更优雅的写法,我的代码如下:
List<GpbCodesAndVersions> versionOneGeneral = lst.stream().peek(x -> { List<General> generals = x.getContent().stream().filter(y -> y.getStatus().equals(1)).toList(); x.setContent(generals); }).filter(z -> !z.getContent().isEmpty()).toList();
优化方案
你的代码虽然能实现需求,但peek操作修改了原列表中的GpbCodesAndVersions对象,这不符合Stream API的设计初衷(peek主要用于调试,而非修改元素状态)。更优雅的写法应该是创建新的对象实例,避免对原数据产生副作用,同时让逻辑更清晰:
List<GpbCodesAndVersions> versionOneGeneral = lst.stream() // 先筛选出content中包含status=1的General的GpbCodesAndVersions .filter(gpb -> gpb.getContent().stream().anyMatch(gen -> gen.getStatus().equals(1))) // 为符合条件的对象创建新实例,仅保留status=1的General .map(gpb -> new GpbCodesAndVersions( gpb.getCode(), gpb.getVersion(), gpb.getContent().stream() .filter(gen -> gen.getStatus().equals(1)) .toList() )) .toList();
优化点说明:
- 提前用
filter过滤掉不需要处理的对象,减少后续map操作的计算量 - 通过
map创建新对象,避免修改原列表元素,保持数据不可变性,更贴合函数式编程风格 - 逻辑拆分明确,每一步操作的职责清晰,可读性更强
如果你的GpbCodesAndVersions类没有现成的对应构造函数,也可以添加复制构造函数简化对象创建:
// 在GpbCodesAndVersions类中添加复制构造函数 public GpbCodesAndVersions(GpbCodesAndVersions original, List<General> newContent) { this.code = original.getCode(); this.version = original.getVersion(); this.content = newContent; } // 对应的Stream写法 List<GpbCodesAndVersions> versionOneGeneral = lst.stream() .filter(gpb -> gpb.getContent().stream().anyMatch(gen -> gen.getStatus().equals(1))) .map(gpb -> { List<General> filteredContent = gpb.getContent().stream() .filter(gen -> gen.getStatus().equals(1)) .toList(); return new GpbCodesAndVersions(gpb, filteredContent); }) .toList();
内容的提问来源于stack exchange,提问作者HudsonHornet
相关产品推荐
相关产品推荐

