流程控制语句这块内容是所有编程入门教材里几乎雷打不动的第三章也是我当年第一次觉得“代码不再是死例子”的分水岭程序终于能根据条件拐弯、能重复干一件无聊事十万遍而不抱怨。不管你是零基础自学Java、C还是Python把流程控制这几个字吃透后面的类、对象、框架全都是在它上面盖楼。这篇我把最常见的几种分支和循环语法拆开揉碎连同我踩过的坑和习惯写法一起记录下来给你做个参考。1. 内容整体设计与思路拆解1.1 为什么流程控制语句是“程序员的第一道坎”在我带过的新人里几乎每个人前几节课都能跟得上一到流程控制就开始迷糊。原因不难理解前面学变量、运算符本质上是“把数据装进盒子、做简单加工”思维还是线性的——从左到右、从上到下一行一行执行。而流程控制语句第一次打破了这种线性程序会“跳着走”会“回头走”甚至会在某个条件满足时直接绕开一大段代码。这个转变其实和我们日常做事的逻辑完全一致。打个比方你早上出门如果下雨就带伞这就是分支只要手机没电就充电充到满再拔这就是循环。流程控制只是把这些生活规则翻译成编译器能读懂的语法难不在语法本身难在思维上要从“写完就结束”切换成“考虑所有可能性”。这就是我把这一章看得比后面任何一章节都重要的原因它决定了你写代码是“死记模板”还是“真正会干活”。1.2 顺序、分支、循环程序的“三驾马车”任何复杂的程序拆到最底层都只剩三种结构顺序、分支、循环。顺序结构最简单就是代码一行行往下执行像列队点名点到谁谁出列。分支结构用if、switch这些关键字来表达核心思想是“根据条件的真假走不同的路”。循环结构用for、while来表达核心思想是“同一段代码反复执行每次执行条件都重新判断一次”。三种结构可以互相嵌套分支里有循环循环里有分支循环套循环都是常态。但无论套多少层单看每一层都是这三种基本形态之一。所以学流程控制不要急着背每种语法的模板先在心里建立这个模型我写的每一行代码要么在顺序执行要么在判断分支要么在循环重复。有了这个整体认知后面看别人写的复杂源码你就能一层层像剥洋葱一样把它还原成这三种结构。2. 分支语句让程序学会做决定2.1 if-else的五种常见写法与执行原理if-else是我们日常用到最多的分支语法。它最基本的形态是if后面跟一个布尔表达式表达式的结果为true就执行if大括号里的代码块为false就跳过这段执行后面的内容。加上else之后false的情况会进入else分支。这里必须强调一个原则if和else匹配的是“语句块”不是单条语句所以哪怕大括号里只有一行代码我也建议你写上大括号。在实际项目里我习惯把if-else的写法归成五种从简单到复杂分别是单if、if-else、if-else if-else、嵌套if、三元运算符简化。单if适合只需要在某个条件成立时做处理。if-else适合两选一。if-else if-else适合多条件互斥的情况例如成绩等级判断A、B、C、D、F只能选一个。int score 87; if (score 90) { System.out.println(优秀); } else if (score 80) { System.out.println(良好); } else if (score 60) { System.out.println(及格); } else { System.out.println(需要补考); }这段代码看着简单但至少有两点操作细节值得注意第一条件的顺序很重要从高分到低分判断一旦某个条件成立后面的else if根本不会执行所以“二选一”和“多选一”的判断顺序绝不能乱。第二别把范围重叠的条件并列写比如先判断score 60再判断score 80那score等于90时会先命中第一个分支后面的判断全部失效。2.2 switch-case的冷知识经典写法与现代写法switch-case适合处理“一个变量的取值能明确枚举出来”的场景比如星期几、月份、菜单选项。它的经典语法是switch(变量)后跟多个case常量匹配成功后执行对应代码块直到碰到break跳出。有一个让无数新手踩坑的点是case穿透如果case后面漏写break程序不会停会把当前case后面所有case的代码一路执行下去直到遇到break或者switch全部结束。int day 3; switch (day) { case 1: System.out.println(周一); break; case 2: System.out.println(周二); break; case 3: System.out.println(周三); break; default: System.out.println(未知); break; }case穿透看起来是坑但用好了反而能简化代码。比如你要统计工作日和周末就可以故意让多个case共用一段逻辑。Java 14之后新增的switch表达式彻底改变了写法不再需要写break用箭头语法配合yield返回值整个switch可以直接作为表达式赋值给变量代码量省不少。我自己的经验是老项目里经典写法还能经常见到但新写的代码能用switch表达式就尽量用表达式可读性好太多。2.3 分支嵌套的尺度别让代码变成“箭头形”分支嵌套是每个初学者都爱干的事一个if里面再套一个if里面再套一个写到六层七层代码往右缩进一大片看起来像个箭头维护起来自己都不想看。我见过最夸张的一段代码嵌套了九层if光是对齐括号就花了好几分钟。避免过度嵌套的常用办法有三个一是提前return把不符合条件的情况直接拦在门外让主逻辑平铺在外面二是把条件提取成布尔变量用带名字的变量代替拖长的表达式三是用卫语句所谓卫语句就是“先判断异常或不重要的情况直接返回或跳过”剩下的主体代码不要包在深层括号里。举个例子要处理一个订单只有订单不为空、状态正常、金额大于零三个条件都满足才执行逻辑新手写法是三个if层层套我更推荐每个条件单独判断不满足就直接return代码立刻变成一条直线。3. 循环语句把重复劳动交给机器3.1 for循环的语法拆解计数器思维for循环是三个循环语法里最常用、也最讲究结构的一个。它的完整语法是for(初始化; 条件判断; 更新表达式)三条语句用分号隔开。执行顺序很固定先执行一次初始化然后判断条件条件为true就进入循环体执行完循环体再执行更新表达式更新完再判断条件如此反复直到条件变成false为止。for (int i 0; i 10; i) { System.out.println(i); }我用一个生活例子解释这就好比做俯卧撑你先定一个计数起点0检查是否做了10个没做够就做一个做完一个计数加一然后再检查……直到计数到10条件不满足循环结束。很多新手会问为什么循环变量从0开始而不是从1开始原因在于数组和列表的下标基本都从0开始用for循环遍历数组时循环变量天然就是下标这是最顺手的配对。写for循环有几件小事容易忽略更新表达式不一定要写i也可以是i2用于每隔一个元素处理一次循环变量可以在初始化时声明这个变量的作用域仅限于整个循环循环结束后再用它就会报错条件判断如果写成i 10循环会多执行一次这种边界错误在超小数据量时感觉不到等数据量大起来就是出大事故的地方。3.2 while和do-while先判断还是先执行while循环和for循环相比更强调“条件为真就继续执行”它适合不知道循环次数、只知道结束条件的场景比如读取文件直到文件末尾或者从用户输入里不断读取数据直到输入quit。while的语法是while(条件)紧跟代码块每次循环前都判断条件条件为false则一次都不执行。do-while和它的区别在于do-while是先执行一次循环体再判断条件。也就是说无论条件满不满足do-while至少会执行一次循环体。这个特性在某些场景下非常有用比如菜单程序无论如何都要显示一次菜单让用户选择选完再根据输入判断是否继续显示这时候do-while就是最贴切的选择。int input; Scanner scanner new Scanner(System.in); do { System.out.println(请输入操作编号0表示退出); input scanner.nextInt(); } while (input ! 0);选择依据就一条这段代码是否必须至少执行一次如果是用do-while否则用while。实际开发里while用得比do-while多得多但do-while这种“至少一次”的语义在特定场景下能把代码写得更直白。滥用while循环导致的问题是变量的更新位置容易漏比如忘了在循环体里修改变量循环条件永远成立就成了死循环后面我会专门讲。3.3 增强for循环与集合遍历的注意事项增强for循环Java里叫for-each表面上是给遍历集合和数组用的简化写法底层其实还是迭代器或者下标遍历。语法是for(元素类型 变量名 : 容器)每次循环自动取出一个元素赋给变量不需要手动管理下标也不容易越界。ListString list Arrays.asList(Java, Python, Go); for (String lang : list) { System.out.println(lang); }用增强for循环时有一个经典限制不能在循环体里直接修改集合的结构比如向正在遍历的List里add或remove元素。原因很简单增强for循环内部依赖了迭代器当你遍历到一半时修改了集合的modCount计数迭代器会立刻抛出ConcurrentModificationException。我见过一个同事排查这个问题排查了两小时最后发现是遍历Map时顺手删了一条数据。如果需要边遍历边删除正确的做法是用迭代器的remove方法或者先收集要删除的元素循环结束后统一删除。4. 流程控制关键字break、continue与标签4.1 break和continue的适用场景break和continue是两个经常被放在一起讲的关键字。简单说break用在循环里作用是立即结束整个循环循环后面的代码继续执行continue用在循环里作用是跳过本次循环的剩余代码直接进入下一次循环。注意关键词的差别一个结束全部一个跳过本次。for (int i 0; i 10; i) { if (i 3) { continue; // 跳过 i3 这次输出 } if (i 7) { break; // 循环在 i7 时直接结束 } System.out.println(i); }这段代码的输出是0、1、2、4、5、6i等于3时被continue跳过i等于7时break把整个循环切断。实际写代码时我建议break和continue后面不要跟过多复杂的判断逻辑一旦break条件复杂到需要写注释才看得懂更好的做法往往是重构循环内部结构把条件提取成单独的方法。continue则要特别注意别滥用它用多了会让循环逻辑变得支离破碎维护者要跳着读代码。4.2 带标签的break跳出多重循环的“逃生通道”多重循环嵌套是流程控制里最容易写晕的地方。比如你写了两层for循环内层循环判断到某个条件时想直接结束外层循环这时普通break只跳出内层循环外层循环还会继续跑结果就是你明明想中断整个查找程序却还在做无用功。解决方案是用带标签的break这是Java保留的一个冷门但好用的语法。outer: for (int i 0; i 5; i) { for (int j 0; j 5; j) { if (i * j 6) { break outer; } System.out.println(i - j); } }标签语法是给某个循环起个名字写在循环语句之前后面跟冒号。break后面带上标签名就能直接跳出标签指定的那一层循环无论嵌套了多少层。这里有一个细节常被忽略标签必须紧贴你想跳出的那层循环不能随便乱放。我个人的看法是带标签的break虽然能解决问题但代码可读性并不好因为标签不是常见语法同事阅读时需要额外停下来理解。如果是自己的项目我更倾向于把深层循环抽取成一个方法在满足退出条件时直接return这样语义更清晰。4.3 return在流程控制里的特殊地位return本质上不是循环控制关键字而是方法结束关键字但它和循环结合得非常紧密。当return写在循环内部时一旦执行不仅循环被终止连整个方法都会立刻返回后面的所有代码都不会执行。这一特性在排查错误时特别有用我在前面讲卫语句时提过其实卫语句本质就是提前return。public boolean checkData(int[] arr) { for (int value : arr) { if (value 0) { return false; } } return true; }这段代码判断数组中是否有负数只要发现一个负数直接返回false后面的元素不再检查。很多人一开始会写一个布尔变量存状态循环结束后再返回其实完全没必要。学会在循环里用return是代码简洁化的一个重要分水岭。但也要注意return写多了会让方法有多个出口调试起来要做更多分支跟踪所以我的习惯是简单判断场景用提前return提升可读性复杂业务方法尽量保持单一出口让代码在修改时更可控。5. 常见问题与排查思路实录5.1 新手最容易翻车的几个细节我在代码评审和帮人调试时总结出流程控制这块出现频率最高的几个问题整理成一张速查表你对号入座检查一下自己有没有犯过问题现象根因解决方案if条件判断不进入分支比较字符串用了而不是equals字符串内容比较全部用equals方法switch执行了多个casecase后面漏写break检查是否存在case穿透循环多执行一次条件里用了而不是确认循环区间考虑边界值疑似死循环程序卡住循环体里没有更新循环变量在循环体内修改变量或使用break遍历集合时抛异常遍历过程中直接增删元素用迭代器remove或收集后统一删除这里额外说一下字符串比较那个问题它是流程控制里非常隐蔽的坑。如果你用比较两个字符串Java里比较的是对象引用地址而不是字符串内容哪怕两个字符串内容一模一样只要它们是不同对象结果也是false。这个错误在局部变量场景下往往表现正常因为常量池可能让两个相同字面量指向同一个对象但在用户输入或方法返回的场景下马上暴露。我的建议是碰到String和基本类型的包装类做比较一律用equals()千万别用。5.2 死循环的现场排除方法死循环是流程控制相里最让人头疼的错误表现就是程序窗口卡死、CPU占用飙到100%。常见的死循环原因有三种循环条件永远为true、循环变量没有更新、break永远执行不到。排查方法我有一套固定流程先在怀疑的循环入口处加打印语句输出循环变量和当前条件判断值如果加了打印还是看不到输出说明循环可能根本没进入此时检查进入循环之前的条件如果能进循环但变量值不变化优先检查更新表达式是否被continue跳过。举一个我实际遇到的例子某次线上一个定时任务卡死日志停留在某个区间不再变化。排查之后发现循环体内有一个条件分支满足该分支时执行了continue而continue的位置在循环变量更新之前。由于continue直接跳到了下一次循环判断更新语句被跳过了循环变量一直不变条件永远成立直接死循环。这个例子很有教学价值continue虽然好用但它会跳过循环体里continue后面的所有代码包括更新表达式。以后看到continue眼睛要警觉起来警惕它的位置和更新语句的先后关系。5.3 综合示例用流程控制拼出一个菜单系统纸上谈兵再多也不如实操一遍。我建议你找个小场景把分支、循环、break、continue、return全部用上。下面这段代码是我常拿来练手的例子一个简单的命令行菜单涵盖do-while、if-else、switch和break的配合使用。public class MenuDemo { public static void main(String[] args) { Scanner scanner new Scanner(System.in); int choice; do { System.out.println(1. 存款 2. 取款 3. 查余额 0. 退出); choice scanner.nextInt(); switch (choice) { case 1: System.out.println(执行存款操作); break; case 2: System.out.println(执行取款操作); break; case 3: System.out.println(执行余额查询); break; case 0: System.out.println(谢谢使用); break; default: System.out.println(无效选项请重新输入); break; } } while (choice ! 0); scanner.close(); } }这个例子不大但你回头分析一下它把这一章的知识点串联起来了do-while保证菜单至少展示一次switch处理选项分支break防止case穿透条件判断传给while决定何时退出。把它跑通之后你可以自己加需求比如输入负数时报错并continue或者把存款金额做成数组统计总额。带着需求去改代码比照着抄十遍更有用。在流程控制这块学习上我个人的经验总结起来就一句话语法三分钟能记住边界问题和执行顺序却要反复琢磨。比起背规则我更建议你把每种结构的执行顺序画成流程图哪怕是手画遇到条件分支就把两个箭头标上真假遇到循环就把判断节点圈出来。画完之后你会发现所谓流程控制本质不过是一个个箭头的组合看懂了箭头方向代码的执行逻辑就再也骗不了你。如果后面学到数组和集合回头再写几遍循环遍历那种“原来如此”的贯通感会非常强烈。
企业数字化 ERP 产品动态
相关推荐
JSP+MySQL在线医疗预约挂号系统源码实战:环境搭建、核心业务与避坑指南 简介:这是一套基于JSP与MySQL开发的在线医疗预约挂号管理系统源码,面向计算机专业学生、Java Web初学者及需要课程设计或毕业设计参考的开发者,帮助解决医院挂号流程数字化、科室与医生排班管理等实际问题。压缩包共206个文件,约1… · 2026/9/26 5:38:57
MySQL查询优化实战:从去重、排序到索引与锁的全面排查指南 1. 从热搜词里看大家最常摔跤的地方这段时间帮几个团队看MySQL问题,顺手刷了一圈大家搜得最多的查询相关内容,"sql语句去重查询""in查询语句报错""mysql排序""mysql将字符串转为日期""mysql中int5"这… · 2026/9/26 5:38:57
MySQL事务与锁机制:高并发下数据一致性的核心实践 前几天线上有个订单服务在处理并发库存扣减时,库里出现了负数库存。我翻了两小时日志,最后定位到的问题并不在业务逻辑,而是事务没包住边界、锁没有按预期兜底。说真的,只要你的系统要同时处理多人下单、多人抢购、多节点并发写数… · 2026/9/26 5:38:57
学习C语言,奔赴Java,夯实编程之路 哈喽各位CSDN的小伙伴!作为一名计算机专业的学生,编程之路于我而言,是从零到一的探索,也是持续精进的修行。我将C语言作为编程入门的核心基石,在不断的学习、敲代码、踩坑、复盘的过程中,慢慢褪去了对编程的… · 2026/9/26 6:13:27
VS Code Python环境配置:解释器、虚拟环境与调试器诊断指南 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 6:13:20
科幻迷收藏《独立日》片源,私有网盘存素材更稳 说起经典科幻灾难片,很多影迷第一时间就会想到 1996 年的《独立日》。震撼的外星母舰画面、经典的战前演讲,放到现在看依旧很有冲击力,不少科幻迷都想把正版高清片源保存下来,有空随时重刷。不过保存这种大体积高清影片࿰… · 2026/9/26 6:13:20
WinUtil深度解析:PowerShell系统治理脚本集原理与实践 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 6:13:20
Python字符串全解:不可变性、切片、格式化与性能优化 1. 从内存模型开始:为什么Python字符串是不可变的1.1 对象、引用与缓冲:一个赋值语句背后发生了什么刚接触Python时,很多人会把字符串理解成"一串字符",然后把它想象成类似数组的结构。这个理解没错,但不完整… · 2026/9/26 6:13:14
数据库课后习题答案别硬背:当测试用例集刷,效率翻倍 简介:万常选版《数据库原理与设计》课后习题答案资源,覆盖第2至6章及第9章,适合正在学习关系模型、数据库建模、关系数据理论与模式求精的本科生、自学者作为复习与自测材料。压缩包共7个文件,含3个doc参考答案、2个sql示例脚本、… · 2026/9/26 0:00:21
OpenClaw 替代品?Hermes Agent 踩坑实录:macOS 飞书接入 TaoToken 配置 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 0:00:40
向下兼容与向上兼容:接口设计中的兼容性策略与工程实践 一次版本升级事故,是很多团队绕不过去的坎。线上环境里,服务端明明已经上线了新版接口,老的移动端还在照着旧文档传参数。请求一到网关,校验直接拒绝,用户操作失败,客服群炸了锅,开发群里开始互… · 2026/9/26 0:00:46