5.Java流程控制之选择结构
2026/8/20 10:20:26 网站建设 项目流程

Java流程控制之选择结构:让程序学会做决定

选择结构,说白了就是让程序具备“做决定”的能力。

一、程序的三大基本流程

所有程序,无论多复杂,都由三种基本结构组合而成。

结构类型执行方式
顺序结构从上到下依次执行
选择结构按条件选择执行路径
循环结构重复执行某段代码

二、if的三种形态,由简到繁

if是最常用的分支语句,它由3种写法,对应三种场景。

2.1 单分支if:满足就执行

语法简介,如果条件成立,就做某事
语法:

if(条件表达式){//条件为true时执行}
intcas=70;if(cas>60){System.out.println("及格了,继续加油")}//输出:及格了,继续加油

执行流程:先判断条件表达式的结果,如果是true,进大括号执行输出语句,如果是false就跳过大括号中的内容。

2.2 双分支if-else:二选一

语法:“如果成立做A,否则做B”——非此即彼的场景。

if(条件表达式){// 条件为 true 时执行 A}else{// 条件为 false 时执行 B}

经典例子:判断奇偶数。

intnum=7;if(num%2==0){System.out.println(num+"是偶数");}else{System.out.println(num+"是奇数");}// 输出:7是奇数

要点:if 和 else 两个分支有且只有一个会被执行,绝不会都走,也不会都不走。

2.3 多分支 if-else if-else:多条件选一

当有 3 个及以上互斥条件时,用 else if 串起来。

if(条件1){// 满足条件1执行}elseif(条件2){// 满足条件2执行}elseif(条件3){// 满足条件3执行}else{// 以上都不满足时执行(兜底)}

成绩评级是最经典的例子:

intscore=85;if(score>=90){System.out.println("优秀");}elseif(score>=80){System.out.println("良好");// ← 命中这里}elseif(score>=60){System.out.println("及格");}else{System.out.println("不及格");}// 输出:良好

执行逻辑:从上往下依次判断,遇到第一个 true 就进对应分支,执行完直接跳出整个 if,后面的 else if 一律不再看。这叫短路式判断。

⚠️多分支顺序很重要!

写多分支时,条件之间必须互斥且有序。错误示范:

// ❌ 错误写法:把 >=60 写在最前面if(score>=60){System.out.println("及格");// 85分会命中这里!}elseif(score>=80){System.out.println("良好");// 永远走不到}

85 明明应该是"良好",却被第一个条件截胡。写区间判断时记得:范围小的、严格的放前面;范围大的、宽松的放后面;或者用明确的上下界(比如score >= 80 && score < 90),就不会出错。

三、if 语句的 5 个高频坑

坑1:大括号省略带来的"幽灵逻辑"

Java 语法规定:if/else 后面如果只有一条语句,可以省略大括号。但强烈不推荐!

// ❌ 看上去两句都属于 if,其实只有第一句是if(score>=60)System.out.println("及格");System.out.println("恭喜你");// 这句永远都会执行!

第二行打印不受 if 控制,无论及不及格都会输出。新手特别容易被缩进骗了——Java 不靠缩进控制代码块,只看大括号。

💡最佳实践
哪怕只有一条语句,也永远写上大括号{ }。能省掉 90% 的低级 Bug。

坑2:悬挂 else 问题

看这段代码,猜 else 属于哪个 if?

inta=5,b=-1;if(a>0)if(b>0)System.out.println("都大于0");elseSystem.out.println("a <= 0");// 实际输出这个?

答案:else 永远和"最近的、未被匹配的 if"配对。也就是内层的if (b > 0),所以 a=5、b=-1 时输出"a <= 0",逻辑完全错了!

解决办法很简单:老老实实写大括号。

// ✅ 正确写法if(a>0){if(b>0){System.out.println("都大于0");}}else{System.out.println("a <= 0");}

坑3:赋值号=与 比较号==混用

这是所有 C 系语言新手必踩的坑。

booleanisVip=true;if(isVip=false){// ❌ 这里是赋值!不是比较!System.out.println("VIP你好");}// 这段代码把 isVip 改成了 false,条件永远不成立

一个小技巧:写比较时把常量放左边,如if (5 == x),这样误写成=会直接编译报错,从而提前发现。

坑4:浮点直接用==比较

前面运算符篇讲过,浮点数有精度误差:

doublea=0.1+0.2;if(a==0.3){// ❌ 不成立!a实际是0.30000000000000004System.out.println("相等");}

正确做法:判断差值是否小于某个极小值,比如Math.abs(a - 0.3) < 1e-6

坑5:字符串比较用==

String 是引用类型,==比较的是内存地址,不是内容。判断字符串相等要用equals()方法:

Stringrole=newString("admin");if(role=="admin"){// ❌ 大概率为 falseSystem.out.println("管理员");}if("admin".equals(role)){// ✅ 正确写法(常量在前避免 NPE)System.out.println("管理员");}

💡小技巧
写字符串比较时,把字面量放前面:"xxx".equals(var),这样即使 var 是 null 也不会抛空指针异常。

四、if 的嵌套:分支里再分支

if 里面还能再套 if,这是处理复杂逻辑的常用手段。比如"先判断是否登录,再判断是不是 VIP":

booleanisLogin=true;booleanisVip=false;if(isLogin){System.out.println("欢迎回来");if(isVip){System.out.println("尊贵的VIP会员,您的专属权益已生效");}else{System.out.println("开通VIP享受更多特权哦");}}else{System.out.println("请先登录");}

嵌套不宜过深,一般建议不超过 3 层。嵌套太多代码会变成"箭头形",可读性骤降。遇到深层嵌套,可以考虑:① 提前 return 减少嵌套;② 把内层逻辑抽成方法。后面讲方法时会详细讲。

五、switch:多路精准匹配

if-else if-else 虽然万能,但当分支条件都是"拿一个变量跟几个固定值比"时,写起来很啰嗦。比如:

intweek=3;if(week==1)System.out.println("周一");elseif(week==2)System.out.println("周二");elseif(week==3)System.out.println("周三");// ...

这种场景,switch更清爽:

5.1 switch 基本语法

switch(表达式){case1:语句1;break;case2:语句2;break;default:默认语句;break;}

用星期的例子改写:

intweek=3;switch(week){case1:System.out.println("周一:开会");break;case2:System.out.println("周二:写代码");break;case3:System.out.println("周三:改Bug");break;// 命中这里case4:System.out.println("周四:评审");break;case5:System.out.println("周五:上线");break;case6:case7:System.out.println("周末:休息");break;default:System.out.println("输入有误");break;}// 输出:周三:改Bug

5.2 switch 支持哪些类型?

switch 对表达式的类型是有限制的,不是所有类型都能用,新手最容易在这里写错。

类型分类支持的类型不支持
基本类型byte / short / int / charlong / float / double / boolean
包装类型Byte / Short / Integer / CharacterLong / Float / Double / Boolean
引用类型String(JDK 7+)、enum 枚举其他普通对象(老版本)

⚠️long/float/double/boolean 不能放进 switch!

switch (x)时,x 如果是 long/double 类型,会直接编译报错。JDK 24 之前必须严格遵守。这也是面试常考题。

5.3 case 穿透:最经典的坑

switch 的执行机制是:先找到匹配的 case 标签,然后从那一行开始"一路往下执行",直到遇到 break 或 switch 结束。如果漏写 break,后面的 case 语句会被连带执行——这就叫case 穿透(Fall-through)

intn=2;switch(n){case1:System.out.println("一");case2:System.out.println("二");// 匹配到这里case3:System.out.println("三");// ⚠️ 穿透了!default:System.out.println("其他");}// 输出:// 二// 三// 其他

你以为只会输出"二",结果连着"三""其他"全输出了——这是新人 switch 丢分最多的地方。

💡记住
每个 case 分支末尾习惯性加 break,除非你明确要利用穿透特性。

5.4 巧妙利用穿透:合并 case

穿透不全是坏事,它有一种非常实用的用法:多个 case 执行同一段代码时,可以把它们摞在一起。比如判断月份属于哪个季节:

intmonth=5;switch(month){case3:case4:case5:System.out.println("春季");break;case6:case7:case8:System.out.println("夏季");break;case9:case10:case11:System.out.println("秋季");break;case12:case1:case2:System.out.println("冬季");break;default:System.out.println("月份无效");}// 输出:春季

另一个常见例子:同时处理大小写字母(按 W/w 都向上)。这种"故意穿透"是合法且推荐的。

5.5 default 的作用

default相当于 if-else 里的 else——所有 case 都不匹配时执行。它可以省略,也可以放在 switch 的任意位置(不一定非要最后),但习惯上放末尾。

⚠️default 放前面也要加 break!

如果 default 写在 case 前面且没加 break,它会往下穿透到第一个 case 并继续执行,结果往往不是你想要的。所以简单点:default 永远放最后一行,break 正常加。

5.6 switch 与 String(JDK 7+)

从 JDK 7 开始,switch 支持 String 类型了,比如根据操作指令做分发:

Stringcmd="save";switch(cmd){case"add":System.out.println("新增");break;case"save":System.out.println("保存");break;case"del":System.out.println("删除");break;default:System.out.println("未知指令");}// 输出:保存

内部原理:编译器会把字符串转成hashCode()+equals()比较,不是直接比地址,所以能正确匹配内容。但要注意两点:① 区分大小写(“Save” 和 “save” 不同);② 传入 null 会抛 NullPointerException,建议先判空。

六、if vs switch:到底用哪个?

if 和 switch 都能做分支,怎么选?一张表说清楚:

对比维度if-elseswitch
判断条件布尔表达式(区间、大小、复杂逻辑)固定常量值(等值匹配)
适合场景范围判断、复杂组合条件菜单/状态/枚举等离散值匹配
支持类型任意 boolean 表达式byte/short/int/char/String/enum
代码可读性分支少时清爽,嵌套多了变"箭头"多路分支时结构清晰、一目了然
底层效率逐条判断,分支越多越慢跳转表实现,效率相对稳定

一句话口诀:等值匹配用 switch,区间判断用 if;能用 switch 的地方一定能用 if,反过来不行。新手阶段优先掌握 if,switch 当作"等值匹配场景的语法糖"即可。

七、实战案例:三个真实小练习

案例1:判断闰年

规则:能被 4 整除但不能被 100 整除,或者能被 400 整除的是闰年。

intyear=2024;if((year%4==0&&year%100!=0)||year%400==0){System.out.println(year+"是闰年");}else{System.out.println(year+"是平年");}// 输出:2024是闰年

案例2:简易计算器(switch 版本)

输入两个数和一个运算符,输出结果。

inta=10,b=3;charop='+';switch(op){case'+':System.out.println(a+b);break;case'-':System.out.println(a-b);break;case'*':System.out.println(a*b);break;case'/':if(b==0){System.out.println("除数不能为0");}else{System.out.println(a/b);}break;default:System.out.println("不支持的运算符");}

案例3:BMI 身体质量指数

BMI = 体重(kg) / 身高(m)²,分级标准:偏瘦<18.5,正常18.5-24,偏胖24-28,肥胖≥28。

doubleweight=70;// kgdoubleheight=1.75;// mdoublebmi=weight/(height*height);if(bmi<18.5){System.out.println("偏瘦,多吃点");}elseif(bmi<24){System.out.println("正常,继续保持");}elseif(bmi<28){System.out.println("偏胖,该运动了");}else{System.out.println("肥胖,建议就医");}

这里注意:因为前面已经bmi < 18.5不成立,到else if (bmi < 24)时自然就隐含了bmi >= 18.5,所以不必写成bmi >= 18.5 && bmi < 24,代码更简洁。

八、避坑总结:8 条血泪教训

#坑点正确做法
1if 条件写成非 boolean(如if(a=1)必须是 boolean,比较用==不用=
2省略大括号导致逻辑错位哪怕一条语句也加{ }
3else 配对错误(悬挂 else)坚持写大括号,缩进规范
4多分支顺序写反导致被截胡严格→宽松顺序,或写全上下界
5浮点数用==直接比较Math.abs(a-b) < epsilon
6字符串用==比较equals()方法,常量字面值在前
7switch 漏写 break 导致穿透每个 case 末尾加 break(故意穿透除外)
8switch 用 long/float/double/boolean只允许 byte/short/int/char/String/enum

九、动手练习(先自己写再对答案)

练习1:三数最大值
给定三个 int 变量 a、b、c,用 if 找出其中最大的数并打印。提示:可以用 “打擂台” 思想——先假设 a 最大,再依次和 b、c 比较。

练习2:成绩等级(switch 版)
输入 0-100 的分数,输出对应等级:90-100 优秀、80-89 良好、70-79 中等、60-69 及格、0-59 不及格。要求用 switch 实现。提示:利用整数除法score / 10把分数映射成 0-10。

练习3:红绿灯模拟器
定义一个 String 变量 color,值为 red/yellow/green 之一,用 switch 分别输出"停"“等一等”“行”,其他值输出"信号灯故障"。注意处理 null。

练习4:个税计算器(简易版)
假设月薪 taxSalary(已扣五险一金)按以下税率计税:≤5000 免税;5001-8000 部分 3%;8001-17000 部分 10%;17001-30000 部分 20%;>30000 部分 25%。用 if-else if 计算并输出税额。

💡下篇预告 🚀
学完选择结构,你已经能让程序"做决定"了。但很多事情还需要反复做——比如遍历 100 个学生成绩、从 1 加到 100、等待用户输入正确密码——这就要用到循环结构。下一篇我们讲 for / while / do-while 三种循环、break 与 continue 的区别、以及死循环的正确用法,让你的程序真正"跑起来"。

— 本文完 —

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询