news 2026/11/1 10:44:06

Java while循环深度解析:从条件判断到实战场景

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Java while循环深度解析:从条件判断到实战场景

最近带一个新人写需求,他对着一个“直到用户输入exit才退出”的功能发了半小时呆,最后问我:while循环不就是个累加器吗,怎么这里还能当条件判断用?我一听就明白了,很多人对Java中while的理解基本停留在“背语法”阶段——会写while(i<10){i++},换个真实场景就不知道怎么用。

这篇我就把while这个关键字讲透。它远不只是“循环N次”那么简单,它是Java里唯一一个真正以“条件是否成立”作为唯一驱动力的循环结构,在处理用户输入、轮询状态、队列消费、菜单系统、数学迭代这些“不知道要循环几次”的场景里,它是绝对的主力。适合所有Java初学者、准备面试的求职者,以及写业务代码但想提升循环技巧的工程师。

1. while循环的底层运行逻辑,以及它和for的本质差异

1.1 语法拆解:条件评估的精确时机

先看一段最基础的Java代码:

int i = 0; while (i < 5) { System.out.println("当前 i = " + i); i++; } System.out.println("循环结束后 i = " + i);

输出结果是:

当前 i = 0 当前 i = 1 当前 i = 2 当前 i = 3 当前 i = 4 循环结束后 i = 5

执行流程其实是这样的:先执行i < 5这个布尔表达式的求值,如果为true,就进入循环体执行大括号里的代码;循环体跑完一遍之后,再次回到条件判断处重新求值,而不是直接进入下一轮。只有当条件表达式的结果为false时,循环才会结束,程序继续执行while语句后面的代码。

这里面有一个特别容易忽略的细节:条件表达式是在每轮循环体执行之前被评估的,也就是说,如果一开始条件就不满足,循环体一次都不会执行。这个特性和Java的另一个变体do-while完全不同,后面我会专门讲。

我见过不少新手写循环时,把条件表达式放在循环体里才更新,导致第一轮判断永远为true,结果就死循环了。比如:

int i = 0; while (i < 5) { System.out.println("输出中"); // 忘记写 i++,或者 i++ 写在条件判断“不可能到达”的分支里 }

这个代码刚跑起来你就会发现,控制台疯狂刷屏,因为i的值永远是0,i < 5永远成立,循环永远出不来。这是while循环最经典的踩坑现场。

1.2 既然有for循环,为什么还要while

很多初学者会问:Java里for循环也能实现同样的效果,而且写法还更紧凑,为什么还需要while?

关键在于“循环次数是否已知”。for循环的语义是“我已经知道要循环几次了,你来按计数器执行”,它的三要素(初始化、条件、步进)天然就是为“固定次数遍历”设计的。比如遍历数组、生成1到100的累加和,用for最直观。

而while的语义是“我不知道要循环几次,只要条件成立你就继续”。这种场景在真实业务里特别多:

  • 从Scanner里持续读取用户输入,直到用户输入了特定命令才停止。
  • 持续从队列里取任务,直到队列空了。
  • 不断轮询某个服务的状态,直到状态变成“完成”。
  • 读取文件流,直到读到文件末尾。
  • 做数学迭代计算,直到误差小于某个阈值。

这些场景的共同点是:循环的结束条件不是由计数器决定的,而是由外部输入、业务状态或者计算精度决定的。用for当然也能写,但读起来会很别扭,因为你要额外定义一个计数器,而这个计数器本身和业务无关。

可以打个比方:for循环像是数着步数走路,“走1步、走2步、走3步”,而while循环像是等公交车,“车没来就继续等,车来了就上车”。前者的“终点”靠步数定义,后者的“终点”靠条件定义。

2. 实战中最常见的while应用场景

2.1 处理用户输入:标准答案里的hasNextInt

在Java入门阶段,while和Scanner组合几乎是必练科目。最典型的例子是读取一组不固定数量的整数,求和后输出:

Scanner scanner = new Scanner(System.in); int sum = 0; while (scanner.hasNextInt()) { int num = scanner.nextInt(); sum += num; System.out.println("当前累加值:" + sum); } System.out.println("最终总和:" + sum); scanner.close();

这个代码的逻辑是这样的:scanner.hasNextInt()会阻塞等待用户在控制台输入,如果输入的是整数,条件为true,循环体累加;如果输入了非数字字符(比如q)或者到达输入流末尾,条件变为false,循环退出。

这里有个特别容易踩的坑:在IDEA的控制台里运行这段代码时,如果你输入了1、2、3然后直接按Ctrl+D(Windows/Linux)或者Ctrl+Z(Windows控制台),输入流才会结束,程序才会输出最终结果。很多人以为按回车就等于结束,结果发现循环还在等你继续输入。这个行为在本地控制台和在线OJ平台上的表现不完全一致,调试的时候不要惊慌,先确认是不是输入流结束符的问题。

类似的模式也常见于文件读取:

BufferedReader reader = Files.newBufferedReader(Paths.get("data.txt")); String line; while ((line = reader.readLine()) != null) { System.out.println("读到一行:" + line); }

reader.readLine()在读到文件末尾时会返回null,所以直接用while ((line = reader.readLine()) != null)就能完成“一直读直到读完”的逻辑。这种赋值和判断写在一起的语法初看很奇怪,但是这是Java社区处理流式读取的惯用写法,看多了就习惯了。

2.2 状态轮询与队列消费

在实际的后端业务里,while最常见的角色是“轮询器”。比如我们需要等待一个异步任务完成,任务状态存储在某个地方,就可以用一个while循环不停去查询:

String taskStatus = queryTaskStatus(taskId); while (!"SUCCESS".equals(taskStatus) && !"FAILED".equals(taskStatus)) { System.out.println("任务还在执行中,当前状态:" + taskStatus); Thread.sleep(1000); // 等1秒再查一次 taskStatus = queryTaskStatus(taskId); } System.out.println("任务最终状态:" + taskStatus);

注意这里必须有一个Thread.sleep或者至少是某种让出CPU的机制,否则就是一个毫无间隙的忙等(busy-wait),会白白烧掉一个CPU核心的资源。在真实项目里,这种轮询一般会配合重试次数上限、超时时间、分布式锁等机制使用,避免某个任务卡死导致永久轮询。

再比如说,使用BlockingQueue做多线程生产者消费者时,消费者线程经常这么写:

while (true) { try { Task task = queue.take(); // 队列为空时阻塞等待 handleTask(task); } catch (InterruptedException e) { Thread.currentThread().interrupt(); break; } }

这里的while (true)不是死循环,而是一个“永真循环 + 中断条件”的结构。线程在queue.take()上阻塞,一旦有任务进来就取走处理,如果线程被外部中断,就通过InterruptedException跳出循环。这是Java多线程编程里的经典写法,几乎每个用到阻塞队列的项目里都能看到它。

2.3 “永真循环+break”模式:菜单系统和服务器循环

在很多单机应用里,菜单系统是一个特别经典的while场景:

Scanner scanner = new Scanner(System.in); while (true) { System.out.println("1. 查询余额"); System.out.println("2. 取款"); System.out.println("3. 存款"); System.out.println("4. 退出系统"); System.out.print("请输入选项:"); int choice = scanner.nextInt(); if (choice == 4) { System.out.println("系统已退出,欢迎下次使用"); break; } switch (choice) { case 1 -> System.out.println("余额:1000元"); case 2 -> System.out.println("取款功能开发中"); case 3 -> System.out.println("存款功能开发中"); default -> System.out.println("无效选项,请重新输入"); } } scanner.close();

这种“展示菜单 → 处理选择 → 再展示菜单”的结构,天然就适合while(true)。因为菜单至少要展示一次,展示之后根据用户的选择决定是否退出,退出条件不是一开始就能确定的。

服务器编程里同理,比如一个简单的Socket服务:

ServerSocket serverSocket = new ServerSocket(8080); while (true) { Socket socket = serverSocket.accept(); // 阻塞等待客户端连接 new Thread(() -> handleClient(socket)).start(); }

serverSocket.accept()会一直阻塞在这里,直到有客户端连接进来,然后创建一个线程去处理这个连接,自己再回到循环里等待下一个连接。没有这个while(true),服务器就只能处理一个客户端就退出了,这显然不是我们想要的。

为什么这里不用for呢?因为循环次数是完全无法预知的。你不可能提前知道今天会有多少个用户访问你的服务,所以只能“来一个处理一个,没人来就等着”,这正是while的设计初衷。

3. while、do-while与for的选择对比

3.1 do-while:至少执行一次的while

Java里有三个循环结构:for、while、do-while。前面说过while是先判断后执行,那do-while恰好反过来:先执行一次循环体,再进行条件判断。语法如下:

int i = 0; do { System.out.println("执行了一次,i = " + i); i++; } while (i < 3);

输出:

执行了一次,i = 0 执行了一次,i = 1 执行了一次,i = 2

关键区别在于:当初始条件不成立时,while一次都不执行,而do-while至少执行一次。用更直观的方式记忆:while是“先问后做”,do-while是“先做后问”。

C语言里也有这个区别,很多学过C的人会拿while和do-while做对比。其实意思是相通的,核心记忆点就是“至少要执行一次”这个特性。

那什么场景必须用do-while?最典型的就是“登录重试”:

String password; do { System.out.print("请输入密码:"); password = scanner.nextLine(); } while (!"123456".equals(password)); System.out.println("密码正确,登录成功");

无论用户第一次输对还是输错,提示语都至少要显示一次,这种情况用do-while比while更自然。如果硬要用while,就得先给变量赋一个永远不会匹配的初始值,比如:

String password = ""; while (!"123456".equals(password)) { // ... }

这样也能实现,但看起来就很绕。所以当你明确知道“循环体至少需要执行一次”的时候,直接选do-while。

3.2 Python的while-else与Java的结构差异

热词里有人在搜“python中while如何退出循环”,这说明很多人在不同语言间切换时会有困惑。Python的while和Java的while在语法形式上非常相似,主要的区别在于Python有一个Java没有的结构叫while-else:

i = 0 while i < 3: print(i) i += 1 else: print("循环正常结束")

在Python里,else会在循环条件变假、循环正常结束时执行;但如果循环是被break强行终止的,else就不会执行。Java没有直接对应的语法,不过可以用一个标志位来实现同等效果:

boolean completed = true; int i = 0; while (i < 3) { if (某些条件) { completed = false; break; } i++; } if (completed) { // 等价于Python的else块 System.out.println("循环正常结束"); }

这种“标志位”写法在Java里非常常见,也算是一个替代方案。理解了这层对应关系,你再看Python转Java的人写的代码,就不会觉得那个completed变量多此一举了,它是有明确语义的。

3.3 性能视角:到底用哪个循环更快

很多面试官喜欢问“for和while哪个性能更好”,其实在今天JIT(即时编译器)不断优化的背景下,二者的字节码执行效率基本没有差异。真正影响性能的,不是外层用for还是while,而是循环体内部的代码质量。

循环优化的核心原则有三个:

  1. 循环体内不要重复计算不变量。
// 差:每次循环都调用 size() for (int i = 0; i < list.size(); i++) { ... } // 好:size() 只调用一次 int size = list.size(); for (int i = 0; i < size; i++) { ... }
  1. 循环体内尽量减少不必要的对象创建和IO操作。

  2. 不要在循环体内定义大对象或者执行耗时操作,如果必须执行,考虑提前退出或分批处理。

说白了,循环的性能瓶颈通常不在循环结构本身,而在循环体里干了什么。for和while的选择更多是语义表达问题,而不是性能问题。

4. 跳出循环的艺术:break、continue、return与标志位

4.1 break和continue:作用范围比你想象的更有限

break在循环里的作用是“立即终止整个循环”,continue的作用是“跳过本次循环的剩余部分,直接进入下一轮判断”。这两个关键字看着简单,但在嵌套循环中有个大坑:break只能跳出它所在的那一层循环。

for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { if (j == 1) { break; // 只会跳出内层j循环,i循环还会继续 } System.out.println("i=" + i + ", j=" + j); } }

如果想要一次跳出多层循环,Java提供了一个带标签(label)的break语法:

outer: for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { if (j == 1) { break outer; // 直接跳出外层循环 } System.out.println("i=" + i + ", j=" + j); } } System.out.println("循环彻底结束");

这个写法很古老,很多人可能没见过,但它在某些场景下真的很好用。比如写一个两层循环查找二维数组里第一个满足条件的元素时,用带标签的break就能省掉一个布尔标志位:

int[][] matrix = {{1, 2}, {3, 4}, {5, 6}}; int target = 4; boolean found = false; outer: for (int i = 0; i < matrix.length; i++) { for (int j = 0; j < matrix[i].length; j++) { if (matrix[i][j] == target) { System.out.println("找到位置:" + i + "," + j); break outer; } } }

有时候网上能看到对标签break的批判,说它像goto一样破坏结构化。我的观点是:适度的标签循环在Java里是合法的,比强行用标志位跳出多层循环读起来更清晰。但如果你发现代码里到处都是标签break,那大概率是循环结构设计有问题,考虑把内层循环提取成一个独立方法,用一个return来替代它。

4.2 安全退出while的三种经典写法

实际开发中,安全退出while循环主要靠这几种方式:

  • 条件变量法:在循环体内更新循环条件中涉及的变量,让条件最终变为false。
int count = 0; while (count < 10) { count++; }
  • 标志位法:用一个布尔变量作为“是否继续运行”的开关。
boolean running = true; while (running) { // 处理逻辑 if (满足退出条件) { running = false; } }

这个方法有一个额外的好处:在while (running)的循环体里,即使有多个嵌套的if分支,你也能很方便地统一控制循环的退出时机。甚至可以在一个方法里设置running为false后,再执行一些收尾操作,再由循环条件自动判断退出。

  • break退出法:在循环体内用break直接跳出。
while (true) { int input = getInput(); if (input == -1) { break; } }

这三种方式没有绝对的好坏。标志位法在“循环体逻辑复杂、退出条件分散”的场景下可读性最好;break在“早退”场景下最简洁;条件变量法适合“自然收敛”的计算场景。我的建议是:写代码时优先保证“这个循环结束的路径是清晰的”,不要出现三种方式混合使用、一个循环里既要改标志位又要break的情况,那会让维护的人非常痛苦。

4.3 经典数学案例:用while实现e的近似计算

热词里有一个非常典型的问题:用while循环计算e = 1 + 1/1! + 1/2! + 1/3! + ...,直到最后一项的值小于10^-4为止。

这道题考察的正是while的数学迭代能力——循环次数事先无法确定,必须依靠“当前项小于阈值”来判断何时停止。

先分析思路:

  • 第0项是1,第1项是1/1!,第2项是1/2!,以此类推。
  • 每一项的分母是阶乘。阶乘计算如果每一步都从1乘到n,效率会很低;更聪明的做法是:n! = (n-1)! * n,也就是在循环中同步维护阶乘值。

实现代码:

double e = 1.0; // 第0项 double term = 1.0; // 当前项,初始为第0项 int n = 0; while (true) { n++; term = term / n; // 这一项 = 上一项 / n,等价于 1 / n! e += term; // 累加到e if (term < 1e-4) { // 当最后一项小于 10^-4 时停止 break; } } System.out.printf("e 的近似值 = %.6f,共累加了 %d 项%n", e, n);

这里最关键的一行是term = term / n;。你可能会问:为什么不是term = 1.0 / 阶乘值?因为分母有连乘关系。当n=1时,第一项是1/1!;当n=2时,第二项是1/2!=(1/1!)/2;当n=3时,第三项是1/3!=(1/2!)/3。用上一项的数值除以当前n就能自然地得到当前项。

如果不用这个递推,写成每次重新计算阶乘的版本:

double e = 1.0; for (int n = 1; ; n++) { long factorial = 1; for (int m = 1; m <= n; m++) { factorial *= m; } double term = 1.0 / factorial; if (term < 1e-4) break; e += term; }

功能上也能实现,但时间复杂度瞬间从O(n)变成O(n²),而且还会遇到factorial溢出的问题。这就是一个很好的例子:同样是循环,好的算法能让程序跑得快、不容易出错,差的算法则可能因为变量溢出得到完全错误的结果。

5. 常见问题与排查技巧实录

5.1 死循环:现场如何快速定位

死循环是while最常见的“翻车现场”,而且通常是在循环体里忘记更新条件变量。我见过一个比较隐蔽的例子,代码里确实写了i++,但是写在了某个永远进不去的if分支里:

int i = 0; while (i < 100) { if (i % 2 == 0) { System.out.println("偶数"); } else { i++; // 这个分支永远进不去,因为 i 一直是偶数 } }

因为i从0开始,i % 2 == 0永远成立,else分支永远不执行,于是i永远不等于奇数,i++永远不触发,i < 100恒为真。

排查死循环,我自己常用的手段是:

  • 限制循环次数或者打印关键变量。在循环体里加一个计数器上限,或者打印一下循环当前的变量值,很快就能看出来哪个变量没更新。
int debugCount = 0; while (condition) { if (debugCount++ > 1000) { System.out.println("检测到疑似死循环,强制退出"); throw new RuntimeException("死循环保护"); } // 业务逻辑 }
  • 用IDEA的Debug模式,在循环体里打个断点,观察变量的值是否在每轮循环后发生变化。这是最直观的方式。
  • 实在要排查一个已经在线上跑起来的死循环进程,可以用jstack抓线程栈,看看线程卡在哪个方法的哪一行。通常看到卡在while循环的那一行,就能锁定问题代码。

5.2 差一错误:循环边界为什么总是多一次或少一次

差一错误(off-by-one error)是循环问题的另一大来源。例如:

int i = 0; while (i < 10) { System.out.println("输出第" + (i + 1) + "次"); i++; }

这个输出10次。但如果你把条件改成i <= 10,就会输出11次。类似地,在处理索引时,很多人会把while (i < array.length)和while (i <= array.length)混用,后者必然会导致数组越界异常:因为数组下标最大是length - 1,当i等于length时再访问array[i]就会抛ArrayIndexOutOfBoundsException。

我的建议是:在写循环时把边界写成一个固定模板,比如遍历数组就用while (i < array.length),遍历集合就用while (iterator.hasNext()),不要每次现想条件,这样可以大幅减少边界失误。如果条件里有多于一个变量参与判断,比如while (i < arr.length && !found),尽量把“终止条件”放在前面。

5.3 哪些while相关面试题最常出现

结合热词里“java面试题”“java八股文”的高频搜索,我把while相关的考题整理一下:

第一类是“while和do-while的区别”,这个前面已经讲透了。面试官一般会追问“如果一开始条件为false,do-while会执行几次”,答案是1次,这是死记硬背也要记牢的点。

第二类是“while(true)会不会导致CPU占用过高”,答案取决于循环体里是什么。如果循环体里有阻塞等待(比如阻塞队列take()、Thread.sleep、IO等待),就不会空转;如果是一个无条件的空循环,那么CPU会飙到100%。这里面试官可能进一步问“如何优雅地让服务循环停止”,回答模式通常是“标志位 + break + 线程中断机制”。

第三类是“用while写冒泡排序”或者“用while计算累加/阶乘”这类纯代码题,考察的是把for的语义迁移到while上的能力。下面这部分就顺便把冒泡排序的while写法展开讲。

5.4 我在实际项目中踩过的while的坑

第一个坑是自动生成SQL的循环遍历。现在很多人用MyBatis-Plus根据实体类生成建表SQL,其实这类工具底层也是用循环遍历实体类的字段列表。我在写类似工具时,第一次用while遍历字段集合,忘记在循环体末尾调用iterator.next(),结果就是同一个字段被无限重复读取,整个服务直接卡死。用增强for循环时这个坑不会出现,因为语法上隐藏了迭代器的next()调用,但换成while遍历Iterator时,一定要记得每轮调用next()。正确写法是这样的:

Iterator<Field> iterator = clazz.getDeclaredFields(); while (iterator.hasNext()) { Field field = iterator.next(); // 这一步必不可少 System.out.println(field.getName()); }

第二个坑是在异常处理里不小心吞掉了退出条件。下面这种“try-catch包住一切”的写法,一旦循环体里抛出异常,异常被吞掉,循环体后面的退出条件更新语句不会执行,循环就永远跳不出去:

List<String> tasks = getTasks(); boolean running = true; while (running) { try { handleTask(tasks.remove(0)); } catch (SomeException e) { // 记录日志 } // 假如remove抛异常时tasks没变,这里会不断处理同一个任务 }

正确的做法是把“循环变量的更新”放在finally块里,或者在catch分支里显式判断是否满足退出条件。比如:

while (running) { try { handleTask(tasks.remove(0)); } catch (SomeException e) { // 处理异常 } finally { if (tasks.isEmpty()) { running = false; } } }

这些坑在常规语法讲解里很少被提到,但真实项目中一个比一个致命。

6. 用while实现几个经典算法:从冒泡排序到24点

6.1 冒泡排序的while写法

热词里有人搜“冒泡排序java”,这里顺带演示一下用while重写冒泡排序。经典的for嵌套版本长这样:

int[] arr = {5, 2, 8, 1, 9}; for (int i = 0; i < arr.length - 1; i++) { for (int j = 0; j < arr.length - 1 - i; j++) { if (arr[j] > arr[j + 1]) { int temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp; } } }

改成while时,核心是保持逻辑不变,只是把变量初始化、条件判断、步进操作分别放到对应的位置:

int[] arr = {5, 2, 8, 1, 9}; int i = 0; while (i < arr.length - 1) { int j = 0; while (j < arr.length - 1 - i) { if (arr[j] > arr[j + 1]) { int temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp; } j++; } i++; }

我看到网上有人把这种写法当作一种“炫技”,其实更重要的是理解它背后的逻辑:for循环的初始化、条件、步进三个表达式,本质上就是while循环的人工拆解。能顺畅地把for转成while,说明你对循环的执行顺序是真的理解了,而不是背下来了。

6.2 用while穷举24点的核心思路

热词里还有“java 算24点”,这个题目用while来穷举非常合适。先说思路:4张牌,有4!种排列方式、5种括号结构、4种运算符组合,总的穷举数量是有限的。用四层while遍历数字排列、运算符组合和括号结构,判断结果是否等于24。

代码会比较长,我这里只给出一个核心穷举框架:

double[] nums = {x1, x2, x3, x4}; char[] ops = {'+', '-', '*', '/'}; boolean found = false; int n = 0; while (n < 4) { int m = 0; while (m < 4) { // 这里固定先计算前两个数,再与第三个运算,最后与第四个运算 // 这只是一种括号排列,完整的24点需要多种括号结构 double result = apply(nums[0], nums[1], ops[n]); result = apply(result, nums[2], ops[m]); result = apply(result, nums[3], ops[某个外层运算符]); if (Math.abs(result - 24) < 1e-6) { found = true; break; } m++; } if (found) break; n++; }

之所以用Math.abs(result - 24) < 1e-6这种绝对值判断而不是直接result == 24,是因为浮点数除法会产生精度误差,比如3 / 7 * 7的结果未必精确等于3。这个经验在其他算法题里同样适用。

完整的24点求解需要更多代码,但核心循环结构就是这个思路。这里我们重点关注的不是写一个完美求解器,而是体会:用while去穷举一个“次数确定但组合复杂”的问题时,循环嵌套和条件退出的设计比具体算法本身更考验逻辑能力。

6.3 循环优化的一个小结:读代码的人比编译器更挑剔

写了这么多样例,我最想表达的一点是:循环是Java代码里出现频率最高、同时也最容易写脏的结构之一。编译器和JIT能容忍你写得不够优雅,但读你代码的人不能。保持循环体短小、条件清晰、退出路径唯一,比任何细微的性能优化都重要。

这一段讲的是循环代码的可维护性问题。for循环因为把初始化、条件、步进都集中在开头,所以非常容易扫一眼就能理解;while循环因为把初始化放在循环前面、步进放在循环体尾部,大脑阅读的负担会稍微大一些。因此,在能够明确表达意图的前提下,简单的计数循环直接使用for;而条件驱动的循环,再用while。这不是性能问题,这是语义问题——让代码说出它想表达的事情。

结尾的几点个人体会

写到这里,我想把这段时间在循环上踩过的坑和体会再掏出来说几句。

我在实际项目中真正用得最顺手、出现频率最高的反而是一个看起来有点“暴力”的模式:while (true)加break,加上try-catch加finally。比如处理消息队列的消费逻辑、实时监听配置变更的订阅逻辑,这种“无限运行直到外部通知停止”的场景,for完全帮不上忙,while加条件变量又显得笨重。while(true)本身就代表“这是一个常驻型循环”,退出时机完全交给内部逻辑来掌控,配合上线程中断、标志位甚至System.exit等机制,反而最直观。

最后再分享一个小技巧:如果你每次写while循环前,先在脑子里问自己三句话——这个循环会执行几次?如果一次也不执行,业务是否还成立?如果要强制跳出,怎么做?——那么80%的while相关bug从一开始就不会存在。我在给团队做Code Review的这三年里,反复看到的问题归根结底都没逃过这三句话。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/11/1 10:43:35

DeepSeek Harness官方桌面端发布:从命令行到可视化Agent工作平台

DeepSeek Harness 官方桌面端终于有了&#xff01;说实话&#xff0c;看到这个消息的时候我第一反应是长舒了一口气。之前折腾命令行版本&#xff0c;虽然功能强悍&#xff0c;但每次配置模型、管理 Skill、分析对话日志都得靠手工敲指令&#xff0c;效率确实有点说不过去。尤其…

作者头像 李华
网站建设 2026/10/16 15:27:07

C#在线考试系统开发实战:从数据库设计到随机组卷算法

简介&#xff1a;涵盖学生、教师、管理员三个角色的C#在线考试系统完整源码包&#xff0c;基于Visual Studio 2010与SQL Server 2008环境开发&#xff0c;适合.NET方向学习者研究Web应用分层架构与在线教育业务实现。项目实现了自动生成试卷、教师自定义题目、学生管理、自动批…

作者头像 李华
网站建设 2026/11/1 10:43:04

手机指挥Codex+Whisper+GitHub:移动端智能体工作流实战

1. 从“拿手机让 dot 帮我干活”说起&#xff1a;一个真实的工作流变革“这几天&#xff0c;我都是拿手机让 dot 帮我干活”——这句话第一次看到的时候&#xff0c;我脑子里蹦出来的不是某个具体工具&#xff0c;而是一种工作方式的迁移&#xff1a;从坐在电脑前敲命令&#x…

作者头像 李华
网站建设 2026/10/24 7:56:23

Codex CLI config.toml 配置指南:接入 OpenAI 兼容接口与报错排查

1. 为什么值得花时间搞懂 config.tomlCodex CLI 是 OpenAI 推出的命令行编码代理工具&#xff0c;它能在终端里直接读写文件、执行命令、跑测试&#xff0c;把"对话式编程"搬到本地工作流里。但很多人装完之后卡在第一步&#xff1a;登录。官方默认走 ChatGPT 账号授…

作者头像 李华
网站建设 2026/10/31 14:17:18

AI Skills工具实战:Skill Hub、SkillsMP等4款Agent技能管理平台解析

1. 从“AI Skills”这个热词说起&#xff1a;它到底在解决什么问题最近半年&#xff0c;如果你混迹在各种AI技术社区&#xff0c;一定频繁刷到“AI Skills”这个词。有人叫它Agent Skills&#xff0c;有人叫Skill Hub&#xff0c;还有人把它翻译成“智能体技能库”。名字听着玄…

作者头像 李华
网站建设 2026/10/16 17:30:28

WPS JS宏正则边界匹配实战:彻底搞懂^、$、\b与断言

在WPS表格里做数据清洗&#xff0c;如果你还在用查找替换一个个处理&#xff0c;而同事已经用JS宏把活干完了&#xff0c;那这篇就是写给你的。最近我接到一批包含8到18位随机编号的报表&#xff0c;本想着正则表达式一把梭&#xff0c;结果在边界匹配上翻了车——不是匹配不到…

作者头像 李华