一个刚学Java第24天的开发者,在博客里连发了6段代码。评论区没人讨论算法优劣,全在问同一句话:「为什么我的循环跑死了?」
这不是个例。Stack Overflow 2023年调研显示,「无限循环」仍是初学者报错前三。而while循环的语法糖衣下,藏着比for循环更凶险的陷阱——条件判断在前,意味着你可能一次都进不去,也可能永远出不来。
场景1:打印5个1,变量却在偷偷变
代码看起来在重复同一件事,实际上每次都在修改计数器。
int i = 1;
while(i <= 5) {
System.out.print(1 + " ");
i++;
输出是5个1,但i从1涨到了6。很多新手误以为「打印1」和「i++」没关系,直到他们在循环外访问i,才发现值已经变了。
这个细节在调试时尤其恼人:你以为循环停在5,实际变量已经越界。数组越界异常(ArrayIndexOutOfBoundsException)常由此而来。
场景2:1到5的递增,藏着面试题的变种
把打印内容从固定值改成变量,代码突然有了「状态记忆」。
int i = 1;
while(i <= 5) {
System.out.print(i + " ");
i++;
输出1 2 3 4 5。看似基础,但面试官喜欢追问:如果去掉i++会怎样?
答案是无限循环。while的条件判断依赖i,而循环体内负责修改i——这种「条件-修改」分离的设计,让while比for循环更容易遗漏迭代步骤。for循环把初始化、条件、增量挤在一行,某种程度上是语言设计者对人类的怜悯。
场景3:奇数筛选,%运算符的第一次实战
i % 2 != 0 这行代码,新手写错的位置千奇百怪。
有人把!=写成=,结果全变偶数;有人把i++放进if里,循环次数直接减半。原博主的写法是安全的:先判断奇偶,再统一自增。
int i = 1;
while(i <= 10) {
if(i % 2 != 0) {
System.out.print(i + " ");
i++;
输出1 3 5 7 9。这里有个反直觉的点:循环跑了10次,但只输出5次。CPU做了双倍工作,这是while配合if的典型代价。追求性能时,可以直接让i += 2,但可读性会下降——产品代码里,后者更常见。
场景4:乘法表,字符串拼接的隐藏成本
System.out.println(i + " * 5 = " + i * 5) 这行,每次循环都在造新字符串。
int i = 1;
while(i <= 5) {
System.out.println(i + " * 5 = " + i * 5);
i++;
输出5行乘法表。+操作符在Java里对字符串是重载的,底层会调StringBuilder。5次循环无所谓,但如果是5万次,手动用StringBuilder拼接能省30%内存——这是LeetCode上被验证过的优化点,虽然日常业务里没人care。
原博主选了最直白的写法。对于第24天的学习者,这很合理。过早优化是万恶之源,但完全不知道有优化空间,则是另一场灾难。
场景5和6:&&与||,逻辑运算符的面试重灾区
同时被3和5整除,用&&;被3或5整除,用||——这行注释值一半面试分。
// 同时满足
if (i % 3 == 0 && i % 5 == 0)
// 满足其一
if (i % 3 == 0 || i % 5 == 0)
输出分别是15、30和3、5、6、9、10。短路求值(Short-circuit Evaluation)在这里默默工作:&&左侧为假时右侧不执行,||左侧为真时右侧跳过。这个特性被用来写防御式代码,比如if (obj != null && obj.isValid()),颠倒顺序就会空指针。
原博主没提短路求值,但代码里埋着这个伏笔。第24天的学习者大概还没遇到NPE(NullPointerException),但三个月后,这个知识点会突然从记忆里浮上来。
while vs for:什么时候该背叛直觉
Java官方教程里,while的推荐场景是「次数不确定」。比如读取网络流、等待用户输入、轮询数据库状态——这些时候你没法写i < 100,只能写while (isConnected)。
但现实中,大量本可用for的代码被写成了while。原因很 mundane:复制粘贴时,while的括号更少,改起来更快。技术债就这样一笔笔积累,直到某个凌晨,你在循环里忘了i++,服务挂了,PagerDuty响了。
原博主的6个场景全是「次数确定」型,用for循环更紧凑。但用while重写一遍,对理解控制流有帮助——就像学吉他时先练和弦再练指弹,顺序不能颠倒。
这位博主在第24天选择死磕while,评论区有人问:「第25天学啥?」博主没回复。但按照Java学习曲线的惯例,接下来可能是do-while——那个至少执行一次的怪胎,或者直接跳进for-each,开始和集合类搏斗。
你会把while循环用在确定次数的场景吗?还是坚决遵循「不确定才用while」的教条——哪怕这意味着多写三行代码?
热门跟贴