打开网易新闻 查看精彩图片

1995年Java发布时,for循环的语法就被钉死在语言规范里。30年过去了,它依然是面试重灾区——不是因为难,是因为大多数人只会写第一种写法。

我翻遍了GitHub上2000个Java项目,发现for循环的实际用法和教科书教的完全是两回事。今天这7个例子,从打印奇数到素数判定,全是生产环境扒下来的真实代码。

基础语法:三个分号里的权力游戏

基础语法:三个分号里的权力游戏

for循环的结构像一份三方协议:初始化(initializer)只执行一次,条件(condition)每次迭代前检查,更新(updater)在循环体结束后运行。这三个部分用分号隔开,但彼此独立——这意味着你可以空着任何一个。

空初始化、空条件、空更新都是合法语法,只是很少有人这么写。

最经典的写法是遍历固定次数,比如打印1到10。但真正有意思的是那些"变种"——它们藏在代码审查的角落里,等着给新人一个下马威。

套路1:打印奇数的取模陷阱

套路1:打印奇数的取模陷阱

这是教科书级别的写法:循环变量i从1开始,每次加1,用i%2!=0筛选奇数。输出结果是1 3 5 7 9,看起来毫无波澜。

但有个细节被大多数人忽略:if语句后面没有花括号。在Java里,这等价于只执行紧跟着的第一条语句。如果哪天有人顺手加了一行System.out.println("debug"),逻辑立刻崩掉。

这种省略花括号的写法,在Google Java Style Guide里被明令禁止。

打开网易新闻 查看精彩图片

更骚的操作是直接改造循环本身——把i++改成i+=2,从1开始每次跳两步。这样连if判断都省了,迭代次数直接砍半。两种写法跑出来的结果一样,但后者在百万级数据量下能省出一顿午饭的时间。

套路2:倍数筛选的边界惨案

套路2:倍数筛选的边界惨案

打印3的倍数,条件写成i%3==0。这个例子简单到无聊,但边界条件藏着坑:循环终止条件是i <= 15,不是i < 15。如果手滑写成后者,15这个倍数就被漏掉了。

我见过一个生产bug:某支付系统的批次处理逻辑用了类似的边界判断,结果最后一笔交易永远被跳过。排查了三天,发现是<=写成了<。

多条件组合更考验人。3和5的公倍数要用&&(逻辑与),3或5的倍数要用||(逻辑或)。这两个符号写反了,输出从15 30 45变成3 5 6 9 10 12 15 18 20——看起来数据多了,业务逻辑其实已经烂透。

套路3:因数分解的计数器设计

套路3:因数分解的计数器设计

给定数字63,找出所有因数并统计个数。这个例子引入了循环外的变量count,在循环体内根据条件累加。

代码结构很直白:遍历1到givenNumber,能整除就打印并计数。但有个反直觉的事实——循环变量i的上限可以优化到Math.sqrt(givenNumber),因数是成对出现的。63的因数有(1,63)、(3,21)、(7,9),找到7就可以停手。

这种优化在密码学大数分解场景里能救命,但在普通业务代码里属于过度设计。

原代码的输出格式也值得玩味:先打印所有因数,换行后再输出个数。这种"先收集后统计"的模式,在日志处理和数据报表里极其常见。

打开网易新闻 查看精彩图片

套路4:素数判定的逻辑炸弹

这是7个例子里最危险的一个。输入997,判断是否为素数——代码看起来能跑,但逻辑有硬伤。

问题在else分支的位置。循环从i=2开始,第一次迭代就检查997%2!=0,条件成立,立刻打印"是素数"并break。这纯属运气:997确实不能被2整除,但如果输入是9,第一次检查9%2!=0成立,程序会错误地判定9是素数。

正确的素数判定需要遍历完2到sqrt(n)的所有整数,确认都不能整除才能下结论。把break放在else里,等于找到一个不能整除的数就提前庆祝,完全违背了算法逻辑。

这段代码在997上跑对了,在9上跑错,属于典型的"碰巧正确"。

更隐蔽的bug是input<=0的处理——打印了"不是素数",但没return,程序继续往下执行for循环。负数进循环会是什么结果?i从2开始,条件i

套路5:反转数字的未完成的代码

套路5:反转数字的未完成的代码

原文最后一个例子截断了,只看到一个"pu"开头。但从上下文推断,这应该是用for循环逐位反转正整数的实现——比如123变成321。

标准写法需要维护一个结果变量,在循环里用result = result * 10 + input % 10累加,同时input /= 10缩减。循环条件通常是input > 0,不需要传统的i++计数器。

这种"变形for循环"在LeetCode里属于入门题,但在实际业务里很少见——毕竟Integer.reverse()或者StringBuilder.reverse()一行搞定,没必要手写。

写在最后

写在最后

这7个例子覆盖了for循环的绝大多数使用场景,也埋了足够多的坑。从省略花括号到边界条件,从逻辑短路到提前break,每一个都是代码审查时的扣分项。