Java switch 语句
switch 语句提供了一种极其优雅的方式,让程序能够根据单个变量的值来执行不同的代码块。当你需要处理一组固定的、已知可能值时,它是冗长乏味的 if-else if-else 链的完美替代品。
掌握 switch 语句对于编写高效且易读的代码至关重要,它能让你以一种高度结构化的方式来应对多重条件分支。
1. 理解 switch 语句
Java 中的 switch 语句允许你根据一个表达式(通常是一个变量)的值,从多个代码块中选择一个来执行。这个表达式只会被评估一次,然后它的值会依次与各个 case 标签中的值进行精确比对。如果找到了匹配项,就会执行该 case 下属的代码块。
1.1 基础语法结构
switch 语句的基本语法如下:
switch (expression) {
case value1:
// 如果 expression == value1,执行这里的代码;
break;
case value2:
// 如果 expression == value2,执行这里的代码;
break;
case valueN:
// 如果 expression == valueN,执行这里的代码;
break;
default:
// 如果 expression 没有任何匹配项,执行这里的保底代码;
}switch (expression): 括号里的expression(表达式) 是你要检测的目标。它的数据类型被严格限制为:byte、short、int、char、String或enum(枚举)。case value1:: 每个case标签指定一个具体的值。如果expression的值与value1完全一致,程序就会从这个标签往下执行代码。break;:break语句极其关键。它的作用是立即终止switch语句,防止代码像瀑布一样“穿透”执行到下一个case。如果没有它,程序会无视后续的条件匹配,直接执行下一个case里的代码。default::default标签是可选的(但强烈建议加上)。如果expression的值没有匹配中上面的任何一个case,程序就会执行default后面的代码,类似于if-else中的最后一个else。
2. break 的重要性:警惕“穿透效应” (Fall-through)
break 语句是控制 switch 内部执行流的开关。如果没有它,程序就会发生“穿透效应 (Fall-through)”,直接滑入下一个 case 并执行其代码,哪怕下一个 case 的值根本不匹配!
虽然在极少数极客场景下这可能是有意为之,但在 99% 的日常开发中,漏写 break 是导致重大 Bug 的元凶。
来看看这个错误示例:
int day = 2;
String dayType;
switch (day) {
case 1:
dayType = "星期一";
case 2:
dayType = "星期二";
case 3:
dayType = "星期三";
default:
dayType = "工作日";
}
System.out.println(dayType); // 输出: 工作日 (糟糕!发生了穿透)解析: 在这个例子中,由于没有任何 break 语句阻拦,代码匹配到 case 2 后,为 dayType 赋值了 "星期二"。但它没有停下,而是继续向下穿透执行了 case 3,最后又穿透执行了 default。最终 dayType 被覆盖成了 "工作日",这显然违背了我们的初衷。
正确写法:在每个 case 后补上 break
int day = 2;
String dayType;
switch (day) {
case 1:
dayType = "星期一";
break; // 匹配成功并执行后,立即跳出 switch
case 2:
dayType = "星期二";
break;
case 3:
dayType = "星期三";
break;
default:
dayType = "工作日";
}
System.out.println(dayType); // 输出: 星期二 (完美!)3. switch 支持的数据类型实战
正如前文所述,switch 表达式仅支持特定数据类型。让我们来看看具体的实战演示:
3.1 整数型 (int)
int month = 4;
String monthString;
switch (month) {
case 1: monthString = "一月"; break;
case 2: monthString = "二月"; break;
case 3: monthString = "三月"; break;
case 4: monthString = "四月"; break;
// ... 省略 5 到 11 月 ...
case 12: monthString = "十二月"; break;
default: monthString = "无效月份";
}
System.out.println(monthString); // 输出: 四月3.2 字符型 (char)
char grade = 'B';
String gradeDescription;
switch (grade) {
case 'A': gradeDescription = "优秀"; break;
case 'B': gradeDescription = "良好"; break;
case 'C': gradeDescription = "中等"; break;
case 'D': gradeDescription = "及格"; break;
case 'F': gradeDescription = "不及格"; break;
default: gradeDescription = "无效等级";
}
System.out.println(gradeDescription); // 输出: 良好3.3 字符串型 (String)
String day = "Monday";
String activity;
switch (day) {
case "Monday": activity = "一周的开始"; break;
case "Tuesday": activity = "第二天"; break;
case "Wednesday": activity = "周中"; break;
case "Thursday": activity = "快熬出头了"; break;
case "Friday": activity = "周末马上到"; break;
default: activity = "周末活动";
}
System.out.println(activity); // 输出: 一周的开始3.4 枚举型 (enum)
首先,在类外部或内部定义一个 enum(枚举):
enum Day {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}然后,在 switch 中丝滑使用它:
Day today = Day.WEDNESDAY;
String message;
switch (today) {
case MONDAY: message = "打工人开启新一周"; break;
case TUESDAY: message = "工作第二天"; break;
case WEDNESDAY: message = "小周末来啦!"; break;
case THURSDAY: message = "疯狂星期四"; break;
case FRIDAY: message = "感谢老天,今天是周五!(TGIF!)"; break;
case SATURDAY: message = "周末万岁!"; break;
case SUNDAY: message = "慵懒的周日"; break;
default: message = "无效的日子";
}
System.out.println(message); // 输出: 小周末来啦!4. 默认分支:default 的作用
default 分支是 switch 语句的可选部分。当所有的 case 都无法匹配目标值时,它提供了一个“兜底/后备”选项。养成写 default 的好习惯,能帮助你优雅地处理无效的输入或未知的异常情况,让代码极其健壮。
int number = 10;
String result;
switch (number) {
case 1: result = "一"; break;
case 2: result = "二"; break;
case 3: result = "三"; break;
default: result = "其他数字";
}
System.out.println(result); // 输出: 其他数字 (因为 10 没有被 case 命中)5. 进阶特性:Switch 表达式 (Java 12+)
如果你使用的是 Java 12 及以上版本,恭喜你,Java 对 switch 进行了史诗级增强,推出了 Switch 表达式 (Switch Expressions)。它不仅让代码更紧凑,还能直接返回值。
int day = 2;
// 直接将 switch 的结果赋值给 dayType 变量
String dayType = switch (day) {
case 1 -> "星期一";
case 2 -> "星期二";
case 3 -> "星期三";
default -> "工作日";
};
System.out.println(dayType); // 输出: 星期二Switch 表达式的杀手级优势:
- 箭头标签 (
->): 替代了传统的冒号:。 - 彻底告别
break: 箭头语法天然免疫穿透效应,匹配完毕直接返回值并退出,再也不用手动写 break 了! - 强制穷举 (Exhaustiveness): 编译器会强制要求你处理所有可能的情况(对于枚举必须列全,对于普通数据类型必须加 default),消除了漏写逻辑的隐患。
- 直接返回值: 箭头右侧的内容就是该表达式返回的结果。
如果你需要在匹配后执行一段复杂的代码(超过一行),你可以使用大括号 {},并通过 yield 关键字来返回值:
int day = 5;
String dayType = switch (day) {
case 1 -> "星期一";
case 2 -> "星期二";
case 3 -> "星期三";
case 4 -> "星期四";
case 5 -> {
System.out.println("周末马上就到啦!");
yield "星期五"; // 使用 yield 关键字返回值
}
default -> "无效的日子";
};
System.out.println(dayType);
// 依次输出:
// 周末马上就到啦!
// 星期五6. 实战演练与演示
为了巩固知识,让我们来看几个真实的业务场景代码。
6.1 示例 1:简易计算器
利用 switch 处理基本的数学运算符。
import java.util.Scanner;
public class Calculator {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入第一个数字: ");
double num1 = scanner.nextDouble();
System.out.print("请输入运算符 (+, -, *, /): ");
char operator = scanner.next().charAt(0);
System.out.print("请输入第二个数字: ");
double num2 = scanner.nextDouble();
double result = 0.0;
switch (operator) {
case '+':
result = num1 + num2;
break;
case '-':
result = num1 - num2;
break;
case '*':
result = num1 * num2;
break;
case '/':
if (num2 != 0) {
result = num1 / num2;
} else {
System.out.println("错误:除数不能为零。");
return; // 结束程序
}
break;
default:
System.out.println("无效的运算符。");
return;
}
System.out.println("计算结果: " + result);
scanner.close();
}
}6.2 示例 2:利用穿透效应合并分支 (月份判断季节)
刚才说穿透效应是 Bug,但如果我们故意利用它,就能让多个不同的值共享同一段代码!
public class SeasonChecker {
public static void main(String[] args) {
int month = 8;
String season;
switch (month) {
case 12: case 1: case 2: // 12、1、2月走到一起
season = "冬季";
break;
case 3: case 4: case 5:
season = "春季";
break;
case 6: case 7: case 8:
season = "夏季";
break;
case 9: case 10: case 11:
season = "秋季";
break;
default:
season = "无效的月份";
}
System.out.println(month + " 月对应的季节是 " + season); // 输出: 8 月对应的季节是 夏季
}
}6.3 示例 3:用逗号分割的现代化 Switch (判断周末)
在 Java 14+ 中,使用新的 Switch 表达式时,你可以直接用逗号把多个值写在一行里,比故意利用穿透效应更直观!
public class DayTypeChecker {
public static void main(String[] args) {
int day = 6; // 1: 周一, 2: 周二, ..., 7: 周日
String dayType = switch (day) {
case 1, 2, 3, 4, 5 -> "工作日";
case 6, 7 -> "休息日";
default -> "无效的日期";
};
System.out.println("周 " + day + " 属于 " + dayType); // 输出: 周 6 属于 休息日
}
}