公司动态
6.Java流程控制之循环结构:让程序“跑起来“
开篇为什么需要循环上篇我们学会了 if/switch让程序具备了做决定的能力。但现实中还有一类任务非常枯燥却必不可少——重复执行同一段代码。想象一下让你把我爱Java打印 100 遍难道要手写 100 行 System.out.println计算 1 到 100 的和难道要 123…100 一行行加让用户反复输入密码直到正确难道要 if 套 if 套 if这时候就需要循环结构登场了。循环让一段代码按规则反复执行直到满足退出条件为止。Java 提供了 3 种循环for、while、do-while外加一个遍历数组/集合用的语法糖——增强 for (for-each)。本文一次讲透配套大量案例和避坑。本篇导读本文带你掌握① for 循环最常用② while 循环③ do-while 循环④ break 与 continue 的区别⑤ 嵌套循环九九乘法表⑥ 死循环的正确用法⑦ 增强 for-each 初体验⑧ 10 个高频避坑 4 道动手练习。一、for 循环已知次数时的首选for 是开发中用得最多的循环结构特点是把初始化、条件判断、迭代更新三要素写在同一行结构紧凑、不易遗漏特别适合已知循环次数的场景。1.1 基本语法for(初始化语句;条件判断;迭代更新){// 循环体要重复执行的代码}三个位置的含义位置作用执行时机典型写法初始化语句定义/声明循环变量循环开始前执行 1 次int i 1条件判断决定是否继续循环每次循环开始前判断i 100迭代更新修改循环变量每次循环体结束后执行i / i–执行顺序是初始化 → 判断条件 → true 则执行循环体 → 迭代更新 → 再判断条件 → …… → false 时退出。1.2 入门案例打印 1~5 与 5~1// 从小到大输出 1 2 3 4 5for(inti1;i5;i){System.out.println(i);}// 从大到小输出 5 4 3 2 1for(inti5;i1;i--){System.out.println(i);}1.3 案例求 1~100 的和累加器模式循环最经典的用法就是累加。记住一个固定套路先准备一个累加器变量 sum 0循环里不断 sum 变量。intsum0;// 累加器初始为0for(inti1;i100;i){sumi;// 等价于 sum sum i;}System.out.println(1~100的和是sum);// 输出 5050套路总结以后题目里出现 “求和”、“统计个数”、“累加”、“累计” 这类字眼脑子里立刻跳出准备一个变量初始化为0 → 循环中不断 或 。求偶数和就在循环体里加个 if(i % 2 0) 判断即可。1.4 案例求所有三位水仙花数水仙花数一个三位数其个位³ 十位³ 百位³ 它本身如 153 1³5³3³ 112527 153。思路循环 100~999逐位拆分判断。for(inti100;i999;i){intgei%10;// 个位intshii/10%10;// 十位intbaii/100;// 百位if(ge*ge*geshi*shi*shibai*bai*baii){System.out.println(i);// 153 370 371 407}}一共 4 个水仙花数153 / 370 / 371 / 407这个题目是面试/考试常客务必敲一遍。1.5 for 的灵活写法for 三个表达式都可以省略但两个分号不能省// ① 省略初始化变量在外面声明inti1;for(;i5;i){...}// ② 省略条件判断相当于永远true成了死循环for(inti1;;i){if(i5)break;// 循环体里自己跳出去...}// ③ 省略迭代更新在循环体里自己改for(inti1;i5;){...i;}// 极端情况三个都省略——经典死循环for(;;){...}⚠️初学者别这么省省略写法是语法允许但日常开发强烈建议把三要素写完整。省略后可读性明显下降而且很容易漏掉更新语句导致死循环。二、while 循环不知道次数时用它while 循环是当型循环——先判断再执行。适合不知道具体循环多少次只知道当某个条件满足时一直做的场景。2.1 基本语法初始化语句;while(条件判断){// 循环体// 迭代更新别漏了}注意while 的初始化语句写在循环外面迭代更新要自己写在循环体里。2.2 for 和 while 可以互相改写// for 版本for(inti1;i5;i){System.out.println(i);}// while 版本等价inti1;while(i5){System.out.println(i);i;}2.3 经典案例纸张折叠超珠峰珠峰高 8844430 毫米一张纸厚 0.1 毫米折叠多少次能超过珠峰——次数未知用 while 最合适。doublepaper0.1;// 纸张厚度毫米intzf8844430;// 珠峰高度intcount0;// 折叠次数while(paperzf){paper*2;// 折叠一次厚度翻倍count;}System.out.println(需要折叠count次);// 27次System.out.println(最终厚度paper);// 约1342万毫米答案是 27 次每次翻倍确实夸张这就是指数增长的力量。⚠️while 小括号后千万别加分号写 while (i 5); { … } 会让分号成为空循环体真正的大括号与 while 无关要么死循环要么逻辑错乱。写完 while 条件直接写大括号别手抖按分号。三、do-while 循环至少执行一次do-while 是直到型循环——先执行一次循环体再判断条件。也就是说无论条件成立与否循环体至少执行 1 次。3.1 基本语法初始化语句;do{// 循环体// 迭代更新}while(条件判断);// ← 这里末尾有分号⚠️do-while 末尾必须加分号这是和 while 的一个关键区别while(…) { } 后面不加分号do { } while(…); 后面必须加分号。记混了就是编译错误。3.2 案例体验先斩后奏inti11;do{System.out.println(Hello);// 仍然会输出一次i;}while(i10);// 条件一开始就是 falseSystem.out.println(ii);// i12虽然初始 i11 已经不满足 i10但 “Hello” 还是被打印了一次——这就是 do-while 的先执行后判断特点。3.3 典型使用场景用户输入校验比如让用户反复输入密码直到正确为止至少要让用户输一次用 do-while 语义最贴切。ScannerscnewScanner(System.in);intpwd;do{System.out.print(请输入密码);pwdsc.nextInt();}while(pwd!123456);System.out.println(登录成功);四、三种循环怎么选对比项forwhiledo-while执行顺序先判后执行先判后执行先执行后判断循环次数已知时首选未知条件首选至少执行1次初始化位置for括号内循环外循环外迭代更新括号内第三处循环体内自写循环体内自写分号问题无括号后别加分号末尾必须加分号使用频率★★★★★★★★★☆★☆☆☆☆一句话记忆次数确定用 for次数不确定用 while至少执行一次用 do-while。实际开发中 for 和 while 占 95% 以上do-while 偶尔用。五、循环控制break 与 continue有时我们不想等循环自然结束而是想中途跳出或跳过某一次这就需要两个跳转关键字。5.1 break立刻跳出本层循环break 的作用是立即终止并跳出当前所在的循环或 switch后面的循环次数全部不再执行。// 找到第一个能被7整除的三位数就停下for(inti100;i999;i){if(i%70){System.out.println(找到i);// 105break;// 直接跳出for}}// break 之后直接到这里5.2 continue跳过本次进入下一次continue 的作用是跳过本次循环剩余的语句直接进入下一次循环的条件判断。注意它不终止整个循环只是这轮我不玩了。// 打印1~10但跳过3的倍数for(inti1;i10;i){if(i%30){continue;// 跳过后面的打印直接i进下一轮}System.out.println(i);// 1 2 4 5 7 8 10}5.3 对比表关键字作用类比理解break跳出整个循环或switch辞职不干了直接走人continue跳过本次继续下一次今天请假明天继续上班带标签的 break/continue了解即可Java 支持给循环起标签名可以一次性跳出多层嵌套循环。例如 outer: for(…) { for(…) { break outer; } } 可以直接从内层跳出外层。初学者暂时不用掌握先把单层 break/continue 用熟。六、嵌套循环循环里套循环循环体里还能再写循环这叫循环嵌套。最经典的例子就是九九乘法表——外层控制第几行内层控制这行打几列。6.1 经典案例九九乘法表for(inti1;i9;i){// 外层行数 1~9for(intj1;ji;j){// 内层列数 1~iSystem.out.print(j*i(i*j)\t);}System.out.println();// 一行打完换行}输出效果示意1*11 1*22 2*24 1*33 2*36 3*39 ... 1*99 2*918 ... 9*981嵌套循环怎么看记住一个诀窍外层循环走1次内层循环走完整轮。外层 i1 时内层 j 循环 1 次外层 i2 时内层 j 循环 2 次……以此类推。多层嵌套同理但日常开发一般不超过 3 层否则性能和可读性都灾难。6.2 案例打印矩形/三角形// 打印 5行5列 星号矩形for(inti1;i5;i){for(intj1;j5;j){System.out.print(* );}System.out.println();}// 打印直角三角形for(inti1;i5;i){for(intj1;ji;j){System.out.print(* );}System.out.println();}七、死循环是 Bug 也是武器如果循环条件永远为 true、或者忘记写迭代更新循环就永远停不下来——这就是死循环。7.1 死循环是怎么造成的// ❌ 漏写迭代更新inti1;while(i5){System.out.println(i);// i 被吃掉了i 永远是1条件永远true}// ❌ for 的迭代更新写错for(inti1;i5;i--){// i 越变越小永远到不了5System.out.println(i);}7.2 故意写死循环服务器/菜单场景死循环不一定是 Bug很多场景下我们故意写死循环然后在循环体内部控制退出。比如// 服务器主循环一直等待用户请求while(true){// 接收请求、处理、响应if(收到退出指令)break;}// 菜单选择ScannerscnewScanner(System.in);while(true){System.out.println(1.查询 2.存款 3.取款 0.退出);intchoicesc.nextInt();if(choice0){System.out.println(再见);break;}// 根据 choice 做相应处理...}while(true) 和 for(; 是两种最常见的故意死循环写法效果完全一样。八、增强 for 循环for-each遍历神器从 JDK 5 开始Java 提供了一种专门用来遍历数组或集合的简化写法——增强 for 循环也叫 for-each。它隐藏了索引代码更简洁。数组我们还没正式讲下一篇会讲这里先给你看一眼长相有个印象8.1 基本语法for(元素类型 变量名:数组或集合){// 直接用变量名代表当前元素}8.2 对比示例int[]nums{10,20,30,40,50};// 普通for要自己管索引 ifor(inti0;inums.length;i){System.out.println(nums[i]);}// 增强for直接拿元素不需要索引for(intnum:nums){System.out.println(num);}8.3 优点和局限维度增强 for 特点优点语法简洁不会数组越界可读性好局限1拿不到当前元素的索引局限2遍历过程中不能删除/添加集合元素会抛异常局限3不能反向遍历、不能跳步适合场景只想把所有元素读一遍不需要索引和修改初学阶段你先记住只要是从头到尾遍历一遍、只读不改增强 for 最省事需要索引或修改元素时用回普通 for。九、避坑总结10 条血泪教训#坑点正确做法1for 括号内三个表达式用逗号而非分号分隔用两个分号 ; 分隔三部分2for/while 循环体漏写迭代更新死循环确保每次循环都能让条件趋向 false3while(…) 后误写分号大括号变独立块条件后直接跟 {不要加分号4do-while 末尾漏写分号} while(条件); 末尾必须有 ;5循环变量作用域搞错for内声明的外部不能用需要外部访问时把变量声明提到 for 外6break/continue 混淆break是走人continue是请假牢记对比表写前想清楚意图7嵌套循环 break 只跳出本层要跳多层用带标签的 break8浮点数做循环变量精度丢失循环变量尽量用 int 整数9在增强for中删除/添加集合元素要用 Iterator 或普通 for 倒序删10循环内声明变量导致每次重新创建性能能提出来的对象尽量提到循环外⚠️重点强调浮点数不要做循环变量看这段代码你猜输出什么for(doublex0;x!1.0;x0.1){System.out.println(x);}答案是死循环因为 0.1 在二进制中是无限循环小数累加多次后会产生精度误差x 永远不可能精确等于 1.0。循环变量请始终使用 int 等整数类型。十、实战案例3 个小练习案例1猜数字游戏系统随机生成 1~100 的整数用户反复猜直到猜对为止每次提示大了或小了。ScannerscnewScanner(System.in);inttarget(int)(Math.random()*100)1;// 1~100随机数intguess;intcount0;do{System.out.print(猜一个1~100的数);guesssc.nextInt();count;if(guesstarget)System.out.println(大了);elseif(guesstarget)System.out.println(小了);elseSystem.out.println(猜对了共猜了count次);}while(guess!target);案例2求 1~100 内能被 3 整除但不能被 5 整除的数的个数intcount0;for(inti1;i100;i){if(i%30i%5!0){count;}}System.out.println(共count个);// 27案例3判断一个数是不是质数素数质数大于 1 的自然数除了 1 和它本身不能被其他数整除。思路从 2 到 sqrt(n) 试除只要能整除就不是质数。intn97;booleanisPrimetrue;for(inti2;iMath.sqrt(n);i){if(n%i0){isPrimefalse;break;// 已经找到因子不用再判了}}System.out.println(isPrime?是质数:不是质数);十一、动手练习先自己写再对答案练习1求阶乘输入一个正整数 nn≤12求 n! 1×2×3×…×n。比如 5! 120。提示准备一个乘积变量初始值为 1不能为0循环里用 * 累乘。练习2打印倒三角形在控制台输出如下图案5行星号倒三角* * * * * * * * * * * * * * *练习3百元买百鸡公鸡5文一只母鸡3文一只小鸡1文3只。用100文买100只鸡问公鸡、母鸡、小鸡各多少只提示双层 for 循环暴力枚举第三只鸡用 100-i-j 计算然后验证钱数。练习4斐波那契数列兔子繁殖问题第1、2项都是1之后每项等于前两项之和1,1,2,3,5,8,13…。请打印前20项。下篇预告 学会了循环你已经能写出会动的程序了。但目前我们手里还都是单个数据处理 100 个学生成绩难道要声明 100 个变量下一篇我们将学习 Java 里最重要的数据容器——数组一维数组、二维数组、Arrays工具类、常见排序查找算法让你的程序能批量处理数据。— 本文完 —