如何将Java嵌套for循环完全转换为Stream流实现
问题解答
完全可以用Stream实现这套校验逻辑,且能彻底避免嵌套循环+flag标记带来的可读性问题。
首先需要注意:你贴出的原始代码存在缩进导致的逻辑偏差——当前代码中if (!flag) return false;写在了内层选课记录循环的每一次迭代中,意味着只要遍历到的第一条选课记录不满足「匹配当前前置课、有成绩、已通过」的条件,方法就会直接返回false,这显然不符合前置课校验的正常业务逻辑。正常逻辑应当是遍历完该学生所有选课记录后,再判断是否满足当前前置课的通过要求,以下实现均基于这个符合业务预期的逻辑编写。
推荐实现(性能+可读性最优)
不需要做两层嵌套遍历,可以先把学生已经通过的课程提前收集为Set,再校验所有前置课是否都在通过集合内即可,时间复杂度从原始嵌套循环的O(n*m)降到O(n+m):
import java.util.Set; import java.util.stream.Collectors; private boolean check(St st) { // 提前收集学生所有有成绩且通过的课程 Set<Co> passedCourses = st.getEns().stream() .filter(en -> en.getGr() != null) .filter(En::hasPassedCo) .map(En::getCo) .collect(Collectors.toSet()); // 所有前置课都在已通过列表中则返回true return getCoPrereqs().stream() .allMatch(passedCourses::contains); }
严格对齐原始代码(含缩进错误逻辑)的实现
如果你需要和你贴出的、带缩进问题的原始代码逻辑100%等价(不推荐,无实际业务价值),也可以用Stream实现,只是需要用原子类模拟可变的flag标记(Lambda中引用的局部变量必须是final或等效final):
import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; private boolean check(St st) { List<Co> prereqs = getCoPrereqs(); List<En> stEns = st.getEns(); return prereqs.stream().allMatch(prereq -> { AtomicBoolean flag = new AtomicBoolean(false); // 内层遍历只要遇到flag为false就直接终止返回 for (En en : stEns) { if (en.getCo().equals(prereq) && en.getGr() != null && en.hasPassedCo()) { flag.set(true); } if (!flag.get()) { return false; } } return flag.get(); }); }
注:如果你的业务场景确实需要保留原始代码的内层逐次判断逻辑,建议优先调整逻辑合理性,再做Stream转换,避免隐藏bug。
内容的提问来源于stack exchange,提问作者pensee
相关产品推荐
相关产品推荐

