Menu

Java while 循环:语法、do-while 与常见陷阱

Java while 循环详解:先判断条件的 while、至少执行一次的 do-while、读取输入直到遇到哨兵值、break 和 continue,以及如何避免死循环。

本页包含可运行的编辑器。编辑、运行,立即查看输出。

没有计数器的时候

for 循环是围绕一个事先设好的计数器构建的。但很多循环并没有清晰的次数:一直读取行直到文件结束,一直询问密码直到输入正确,一直把一个数减半直到它变成 1。对于这些情况,while 循环是最自然的选择:只要条件保持为 true,它就一直重复。

while 循环在每次执行之前都会检查条件,包括第一次。如果条件一开始就是 false,循环体就根本不会执行。

先检查条件 count > 0;如果为 true,就执行循环体;然后回到开头再检查一次。count-- 这一行最终会让条件变为 false,去掉它,循环就会永远运行下去。

while 循环的结构

把它和你已经熟悉的三段式 for 循环比较一下。while 循环把这三项工作拆开了:初始化在循环之前完成,条件写在括号里,更新则放在循环体内部。

int i = 0;              // initialization - before the loop
while (i < 5) {         // condition - checked each pass
    System.out.println(i);
    i++;                // update - you must remember this yourself
}

问题就出在最后这一部分。在 for 循环中,更新紧挨着条件,很难忘记。而在 while 循环中,它只是循环体里的一条普通语句,最常见的 bug 就是漏写它,导致程序卡住。

do-while:循环体至少执行一次

有时你需要先执行一次循环体,才能决定是否要重复。do-while 循环在末尾检查条件,所以循环体总是至少执行一次:

你必须至少提示并读取一次,才能知道输入是否有效,而这正是 do-while 提供的。注意 while (...) 后面的分号,它是必需的,忘了写它是一个常见的编译错误。

当条件一开始就是 false 时,它和普通 while 的区别就非常明显了:

只会打印 do-while body。while 循环完全跳过了它的循环体,因为在第一次检查之前 x < 5 就已经是 false 了。

循环直到遇到哨兵值

while 的一个经典用法是一直读取,直到遇到一个特殊的“停止”值,也就是哨兵值。这里没有计数器,你只是一直进行下去,直到数据告诉你该停了:

这里的模式是:在循环之前先读取一次,然后在每次循环的末尾再读取一次。这样条件检查的永远是最新的输入。如果忘了在循环体里再次读取,value 永远不会改变,你就写出了一个死循环。

while 循环中的 break 和 continue

break 和 continue 在这里的作用和在 for 循环中一样。break 立即离开循环;continue 直接跳回条件检查,跳过本次循环剩下的部分:

这会打印 1 3 5 7 9。while (true) 故意设计成永远不会自己停下来,break 是唯一的出口。在 while 循环中使用 continue 要小心:因为更新是循环体的一部分,如果在推进计数器之前就用 continue 跳回开头,循环就会悄无声息地卡住。上面的例子中 n++ 先执行,所以是安全的。

小心死循环

条件最终必须变为 false,而这完全取决于循环体里有没有东西在改变。最常见的两个原因是忘了更新和更新的方式不对:

int i = 0;
while (i < 5) {
    System.out.println(i);   // i never changes -> runs forever
}
int i = 0;
while (i != 10) {
    i += 3;   // 0, 3, 6, 9, 12... skips right past 10 -> runs forever
}

第一个卡住,是因为 i 从来没有被更新。第二个卡住,是因为计数器跨过了条件要找的那个确切的值。当步长可能无法正好落在目标值上时,优先用 < 或 <=,而不是 !=。while (true) 本身没有问题,前提是它有一个一定会执行到的 break;不小心写出来的死循环就只是一个 bug。

下一页:for-each 循环

当你要循环直到某个条件改变、又没有清晰的计数时,while 循环是合适的工具。但如果你只是想访问数组或列表中的每个元素,不需要索引,也不需要管理条件,那么还有更简洁的写法:增强的 for-each 循环。这就是下一页的内容。

常见问题

Java 中 while 和 do-while 有什么区别?

while 循环在第一次执行之前就检查条件,所以循环体可能一次都不执行。do-while 循环先执行一次循环体,再在末尾检查条件,所以它总是至少执行一次。当你必须先做完某件事才能决定是否重复时(比如先提示输入,再校验输入),就用 do-while。

Java 中什么时候用 while 循环代替 for 循环?

当你没有一个清晰的计数器,只是想一直重复直到某个条件改变时,就用 while 循环:读取输入直到用户输入 quit、轮询直到某个值准备好,或者处理队列直到它为空。如果你知道迭代次数,或者有一个明显可以计数的索引,就用 for 循环。

Java 中如何停止一个无限 while 循环?

确保循环体里有某个操作最终会让条件变为 false(递减计数器、移动指针、设置标志)。对于有意写成的 while (true) 循环,在里面放一个由 if 控制的 break。如果循环卡住了,通常是因为忘了更新条件所依赖的变量。

Coddy 编程语言插图

和 Coddy 一起学编程

开始