switch语句存在于多种高级编程语言中。究其作用,跟 if 分支很像,但具体到用法上却有很多细节需要注意。最近查看了oracle官网的 switch文档 ,写的很是详细,翻译如下,如有错误、请评论指明。
【翻译开始】
switch语句
switch基础概念
与 if-then 、 if-then-else 语句不同,switch语句可以有多种可执行路径。switch可用于基本数据类型——byte、short、char和int——的判断;此外,它还可以判断枚举类型(在枚举类型 讨论)、String类,以及对基本数据类型进行包装的几个特殊类——Character、
Byte、
Short 和
Integer
(在 数字和字符串 章节中讨论)。
下面的代码样例SwitchDemo,声明了一个名为month的int变量,其值表示了某个月份。代码根据month变量的值,通过使用switch语句实现了对该月份名字的输出显示。在这个例子中,August 被打印到标准输出。
public class SwitchDemo {
public static void main(String[] args) {
int month = 8;
String monthString;
switch (month) {
case 1: monthString = "January";
break;
case 2: monthString = "February";
break;
case 3: monthString = "March";
break;
case 4: monthString = "April";
break;
case 5: monthString = "May";
break;
case 6: monthString = "June";
break;
case 7: monthString = "July";
break;
case 8: monthString = "August";
break;
case 9: monthString = "September";
break;
case 10: monthString = "October";
break;
case 11: monthString = "November";
break;
case 12: monthString = "December";
break;
default: monthString = "Invalid month";
break;
}
System.out.println(monthString);
}
}
switch语句的主体又被称为switch语句块。switch语句块中的一条语句可以放在一个或多个case标签或default标签之后。switch语句计算表达式的值,然后执行这个所匹配的case标签之后的所有语句。
当然,你也可以使用 if-then-else 语句来输出月份名字:
int month = 8;
if (month == 1) {
System.out.println("January");
} else if (month == 2) {
System.out.println("February");
}
... // and so on
选择 if-then-else 语句还是 switch 语句,这需要综合考虑可读性和语句所判断的表达式。 一个if-then-else语句可以判断 基于值或条件的范围 的表达式;然而switch语句判断的表达式,只能基于一个单一的整型、枚举值或String对象。
switch中的break语句
(switch中的)break语句也是一个有趣的知识点。switch语句块内的每个break语句是用以终结switch语句的,然后控制流从switch语句块后的第一条语句继续执行。break语句是必要的,否则switch语句块内的语句就会“一泻千里”(fall through):匹配的case标签之后的所有语句会顺序执行,而不管后续case标签的表达式值(即无论匹配与否),直到遇到break语句(如果没有break就会执行直到switch结束)。下面的示例代码 SwitchDemoFallThrough
演示了上文所述的、switch块内语句“一泻千里”的情况。这段代码打印输出了整型变量month对应的月份以及其后续月份的名字。
public class SwitchDemoFallThrough {
public static void main(String[] args) {
java.util.ArrayList<String> futureMonths =
new java.util.ArrayList<String>();
int month = 8;
switch (month) {
case 1: futureMonths.add("January");
case 2: futureMonths.add("February");
case 3: futureMonths.add("March");
case 4: futureMonths.add("April");
case 5: futureMonths.add("May");
case 6: futureMonths.add("June");
case 7: futureMonths.add("July");
case 8: futureMonths.add("August");
case 9: futureMonths.add("September");
case 10: futureMonths.add("October");
case 11: futureMonths.add("November");
case 12: futureMonths.add("December");
break;
default: break;
}
if (futureMonths.isEmpty()) {
System.out.println("Invalid month number");
} else {
for (String monthName : futureMonths) {
System.out.println(monthName);
}
}
}
}
下面是示例代码的输出:
August
September
October
November
December
从技术上讲,最后一个break不是必需的,因为控制流已跳出了switch语句。
在使用switch语句时强烈推荐使用break语句,以便更容易地修改代码、减少出错倾向。default部分负责处理那些所有不明确的、未被case部分处理的值(若所有case都不匹配的值就会交给default来处理)。
下面的示例代码 SwitchDemo2,展示了一条语句怎样拥有多个case标签。该段代码用于计算特定月份的天数。
class SwitchDemo2 {
public static void main(String[] args) {
int month = 2;
int year = 2000;
int numDays = 0;
switch (month) {
case 1: case 3: case 5:
case 7: case 8: case 10:
case 12:
numDays = 31;
break;
case 4: case 6:
case 9: case 11:
numDays = 30;
break;
case 2:
if (((year % 4 == 0) &&
!(year % 100 == 0))
|| (year % 400 == 0))
numDays = 29;
else
numDays = 28;
break;
default:
System.out.println("Invalid month.");
break;
}
System.out.println("Number of Days = "
+ numDays);
}
}
上面例子的输出是:
Number of Days = 29
在switch语句中使用String
StringSwitchDemo,根据String类型的变量month的值来显示对应的月份数。
public class StringSwitchDemo {
public static int getMonthNumber(String month) {
int monthNumber = 0;
if (month == null) {
return monthNumber;
}
switch (month.toLowerCase()) {
case "january":
monthNumber = 1;
break;
case "february":
monthNumber = 2;
break;
case "march":
monthNumber = 3;
break;
case "april":
monthNumber = 4;
break;
case "may":
monthNumber = 5;
break;
case "june":
monthNumber = 6;
break;
case "july":
monthNumber = 7;
break;
case "august":
monthNumber = 8;
break;
case "september":
monthNumber = 9;
break;
case "october":
monthNumber = 10;
break;
case "november":
monthNumber = 11;
break;
case "december":
monthNumber = 12;
break;
default:
monthNumber = 0;
break;
}
return monthNumber;
}
public static void main(String[] args) {
String month = "August";
int returnedMonthNumber =
StringSwitchDemo.getMonthNumber(month);
if (returnedMonthNumber == 0) {
System.out.println("Invalid month");
} else {
System.out.println(returnedMonthNumber);
}
}
}
上面的代码执行输出是8。
switch表达式中的String值与每个case标签的表达式进行比较,这种比较就好像(as if)是使用了String.equals
方法似的。为了让例子StringSwitchDemo
可以不管大小写而接受任意月份名作参数,month变量被特地转化为小写形式(这里使用了toLowerCase
方法),同时所有case标签对应的String表达式也都是小写形式的。
注意:这个例子检查了switch语句的表达式值是否为null。(你也要这样做)保证switch语句的表达式值不是null,以防止抛出NullPointerException
异常。
【翻译结束】
一些编程策略
《编写高质量代码-改善Java程序的151个建议》的第15个建议中,提到了些建议:
- 单元测试(Unit Test),但是不一定能完全覆盖;
- 养成随手在case语句后写上break的良好习惯;
- 或者,修改IDE的警告级别。在Eclipse中,可以依次点击Window -> Preferences -> Java -> Compiler -> Errors/Warnings -> Potential Programming Problems,然后修改“switch” case fall-through为Errors级别,这样如果不在case语句中加入break,Eclipse就会报错。(不过,如果对于专门利用fall-through的高人来说,好像就不恰当了,当然高人一般也不会反如此低级的编程错误)。设置如下图。
参考
1.https://docs.oracle.com/javase/tutorial/java/nutsandbolts/switch.html