如何优雅的跳出多层循环?

2023-11-01 10:45:39 +08:00
 BIGBIG

如何优雅的跳出多层循环?

现有一个数据清洗任务。有多层循环,如下伪代码。 我的问题是:当 cleanedCount 达到 1 百万条数据时,要停止整个清洗任务。难道要一层一层 return 出去么?

class CleanData{

  // 已清洗数据量
  cleanedCount ;

  // 迁移任务
  method cleanByTask() {
    activityIdList.foreach{activityId -> cleanByActivity(activityId)}
  }

  // 按活动
  method cleanByActivity(activityId) {
    tables.foreach{table -> cleanByTable(table)}
  }

  // 按表
  method cleanByTable(table) {
    timeSplits.foreach{timeSplit -> cleanByTimeSplit(timeSplit)}
  }
  
  // 按时间切片
  method cleanByTimeSplit(timeSplit) {
    每 500 条.foreach{500 条 -> cleanByCount(500 条)}
  }

  // 按数量
  method cleanByCount(500 条) {
    cleanedCount += 500
    if (cleanedCount >= 1000000) {
      reurn;
    }
  }

}
3866 次点击
所在节点    Java
32 条回复
nodejsexpress
2023-11-01 13:47:02 +08:00
不用 for, 用 while, 多几个条件 and 一起就好了.
adoal
2023-11-01 13:52:08 +08:00
惰性求值,摊平成迭代器
kyuuseiryuu
2023-11-01 14:06:57 +08:00
do
for each
if something
break
while false
BIGBIG
2023-11-01 14:25:08 +08:00
结案啦:1. 抛出指定异常; 2. 然后捕获异常。优雅永不过时
感谢各位巨佬。


帖子下沉啦
iosyyy
2023-11-01 15:12:08 +08:00
尽量减少循环
baoshijiagong
2023-11-01 16:50:44 +08:00
要看情况,如果“cleanedCount 达到 1 百万条数据” 是异常情况,那么用抛异常,属优雅;如果是正常流程,那么只是形式上的优雅,逻辑上不算。

后者可以用方法函数,将多层的 cleanByXXX 的实现抽象成同一个抽象方法,在这个抽象方法判断 cleanedCount 即可。

新建抽象方法:

public <P, C> void clean(P parentId, Function<P, List<C>> getChildList, Consumer<C> cleanChild) {
if (cleanedCount < 10_000_000) {
List<C> childList = getChildList.apply(parentId);
childList.forEach(cleanChild);
}
}

比如 cleanByTask 改成:

public void cleanByTask() {
clean(null, p -> {
// getActivityIdList
return new ArrayList<>();
}, this::cleanByActivity);
}
gg1025
2023-11-01 17:37:03 +08:00
别问,问就是 goto
KaGaMiKun
2023-11-01 17:40:28 +08:00
第一反应是实现迭代器
但这迭代器使用场景很少,仅仅可能为了这处省个返回才写的,顿时感觉还是不如老实返回
billccn
2023-11-02 07:10:24 +08:00
抛异常就是正解,一些函数式编程语言(比如 OCaml )抛异常是从内层退出循环的唯一的方式,这些语言是研究计编程理论的人喜欢用的,他们都没觉得是抛异常是旁门左道。

有一些老程序员会说尽量不要抛异常,是因为收集堆栈信息会比较慢,但是很多编程语言现在都对异常做了优化。比如 Java 虚拟机能识别这种用于控制程序执行,而不是用于报告错误的异常,抛出这种异常的时候里面就不会有堆栈信息,与创建一个普通对象无异。
mmdsun
2023-11-03 00:35:58 +08:00
fillInStackTrace 抛异常,对性能影响很小。

public final class StopException extends RuntimeException {
public static final StopException INSTANCE = new StopException();

@Override
public synchronized Throwable fillInStackTrace() {
return this;
}
}
leee41
2024-03-14 14:26:42 +08:00
goto label
你看反编译出来的 class 就能经常看到了,这个真有用,你这个场景完美 cover
leee41
2024-03-14 14:28:00 +08:00
代码补充
```
outer: // 这是一个标签
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
if (i * j > 10) {
System.out.println("Breaking from nested loop");
break outer; // 跳出标签指定的循环
}
}
}
System.out.println("Exited loop");
```

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/987376

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX