程序员希望实现这样的功能:如果输入1则打印“石头”,输入2则打印“剪子”,输入3则打印“布”。根据上一小节讲述的多重if...else结构,并以变量x表示用户输入的数字,可以用以下程序实现该功能:
if (x==1) {
System.out.println("石头");
} else if (x==2) {
System.out.println("剪子");
} else if (x==3) {
System.out.println("布");
}
通过观察程序不难发现:在这个题目中,每一个if条件都是判断变量x是否等于一个具体的数值,而不是属于某个范围。针对这种情况,Java语言专门提供了一种更为简洁的程序结构叫做switch,中文翻译为“多路分支”,它的具体写法如下:
switch(x)
{
case 1:
System.out.println("石头");
break;
case 2:
System.out.println("剪子");
break;
case 3:
System.out.println("布");
break;
}
以上代码中,switch关键字的后面是一对小括号,小括号中是变量x,表示接下来要对x的值进行分析和处理。小括号的后面是一对大括号,大括号中出现了多个“case”,每一个case都表示了一种情况。 “case 1:”就表示x==1这种情况。在书写代码时需注意:“case”与“1”之间有一个空格,不可连为一体。当x的值与某个case后面的数字相等时,这个case下面的语句就会被执行,直到出现break关键字为止。以上这段程序使用switch结构清晰的展现出变量x在等于1、2、3的情况下,虚拟机会分别输出石头、剪子、布。
switch结构并不难理解,但读者在使用这个结构的时候还是需要注意一些语法细节:
1.不可随意省略break关键字
上文的代码中,每个case下都有一个break关键字。这个关键字用来跳出switch结构。如果程序员省略了break关键字,并不会出现语法错误,但是虚拟机会在执行完当前case下的语句后,会“跨越”到下一个case的语句中继续执行,例如把原来程序中所有的break都去掉,改为如下形式:
switch(x)
{
case 1:
System.out.println("石头");
case 2:
System.out.println("剪子");
case 3:
System.out.println("布");
}
去掉break后,在用户输入1的情况下,虚拟机会在执行完属于“case 1”的输出语句后继续向下执行属于“case 2”和“case 3” 输出语句,直到switch结构结束,程序执行效果如图2-17所示。
图2-17 省略break关键字的效果
2.case关键字后面只能是常量
从代码中可以看到,每个case关键字后面都是1、2、3这样的常量。程序员不可以先声明“int a=1”,然后用“case a”来代替“case 1”,否则会出现语法错误。如果需要用变量的形式来表示某个常量,必须在这个变量前面加final关键字,使它成为一个常量,之后才能把这个变量的名称写到case关键字的后面。
3.switch结构并不能判断所有类型的变量
这句话的意思是:并不是所有类型的变量都可以被放到switch后面的小括号中。在最早期版本的JDK中,只有byte、short、int和char类型的变量可以被switch结构支持,从JDK1.5开始,switch结构开始支持枚举类型的值,而从JDK1.7开始,又加入了支持String(即字符串)类型的值。关于枚举和String类型的相关知识,本书将在后面的章节中详细介绍。
4.case后面的常量值不能重复
在一个switch结构中,任何两个case后面的常量值都不能重复,否则会出现语法错误。有了这条语法,虚拟机在发现变量x与某个case相匹配之后,就可以确定后面不会再有另外一个可以与之相匹配的case,于是就会立刻停止与后面case的对比并且马上开始执行代码。因此,这条语法能够减少比较次数而大大提高程序的执行效率。
以上讲述的均是用户所输入数字在合理范围的情况。有时候,用户会输入一个不在合理范围内的值,例如在本例题当中,用户如果输入的是数字4,switch结构中任何一个case都不能与数字4匹配,所以程序运行不会有任何输出结果。为了能够在用户所输入的数字不在合理范围的情况下输出一个提示信息,程序员可以在switch结构中加入一个“default”。default也是一个关键字,它可以指定在任何一个case都不能与变量x匹配的情况下虚拟机要执行的语句,通常在编写代码的时候都会把default和属于它的语句放在switch结构的最下方,例如:
switch(x)
{
case 1:
System.out.println("石头");
break;
case 2:
System.out.println("剪子");
break;
case 3:
System.out.println("布");
break;
default:
System.out.println("输入错误!");//x与各个case都不匹配时会执行这条语句
}
此处需要强调:把default放置在switch结构的最下方仅仅是一种代码书写习惯,并非是语法规则。事实上,程序员可以把default和属于它的语句放在switch结构的任意位置。但无论default放在哪里,虚拟机都会先用x与各个case进行匹配,只有在与所有case匹配都不成功的情况下,才会执行default关键字所指定的语句。需要注意:虚拟机一旦开始执行default所指定的语句,同样是出现了break或到达switch结构的末尾才停止。例如把程序改成如下形式:
switch(x)
{
case 1:
System.out.println("石头");
break;
case 2:
System.out.println("剪子");
break;
default:
System.out.println("输入错误!");
case 3:
System.out.println("布");
break;
}
修改后的代码中default位于“case 3”之前,如果用户输入的是数字3,执行结果如图2-18所示。
图2-18 switch结构运行结果示意图1
从图2-18可以看出,当变量x值为3的情况下,与“case 3”匹配成功。在虚拟机自上而下的用x与各个case进行匹配时,曾经“路过”了default,但并没有执行default所指定的语句。这说明在x没有与所有的case完成比较之前,虚拟机不会执行default所指定的代码。
如果用户输入的是数字4,则执行结果如图2-19所示。
图2-19 switch结构运行结果示意图2
从图2-19中可以看出,虚拟机一旦开始执行default关键字所指定的语句,如果没有遇到break或到达switch结构的末尾,也会跨越到下面的case中执行语句。因此,通常情况下程序员都会把default和属于它的语句放在switch结构的最下方。此例题完整代码如下:
【例02_12 石头剪子布】
Exam02_12.java
import java.util.Scanner;
public class Exam02_12 {
public static void main(String[] args) {
int x;
Scanner sc = new Scanner(System.in);
System.out.println("请输入1、2、3当中的一个数字");
x = sc.nextInt();
switch (x) {
case 1:
System.out.println("石头");
break;
case 2:
System.out.println("剪子");
break;
case 3:
System.out.println("布");
break;
default:
System.out.println("输入错误!");
}
}
}
switch结构中,一个case所附带的语句如果没有以break作为结束,虚拟机会在执行程序时跨越到下一个case中执行语句。这个特性有时候可以给编程带来特殊的便利,其中最典型的例子莫过于解决求一年中第几天的问题。该问题要求用户输入一组年、月、日的数值,然后计算出这一天是当年的第几天。解决这个问题的基本思路是:根据所输入的月份值,把该月前面所有的月份的整月天数都加上,然后再加上当前日期。如果是闰年,并且是2月之后的日期,再额外添加1天以补上闰年多出来的天数。例如,输入是5月20日,那么就把5月之前的1-4月的整月天数都加上,然后再加20。如果输入的年份是闰年,则额外再加1天,这样就能算出5月20日是这一年中的第几天。
实际编码时,可以定义一个变量dayNumber 用来表示某日期是这一年中的第几天。dayNumber 的初始值为0。然后在程序中添加一个switch结构,在其中设置12个case,每一个case表示一个月份值。把所有月份的值按从大到小的顺序排列,在每个case中都把前一个月的整月天数与dayNumber 相加。如果每个case中都没有break,则虚拟机跨越多个case执行相加操作,就能实现“累加”效果。这个“累加”的结果就是本月之前所有月份的总天数。在此基础上,把本月的日期也加到dayNumber 中。如果年份为闰年,且月份晚于2月,则为了补上闰年的那1天还需要再给dayNumber 加1。经过这几个步骤之后,dayNumber 的值就是这个日期在当年的第几天。求一年中第几天问题的具体实现代码如下:
【例02_13 求一年中的第几天】
Exam02_13.java
import java.util.Scanner;
public class Exam02_13 {
public static void main(String[] args) {
int year, month, date;// 年月日
int dayNumber = 0;// 一年中的第几天
Scanner sc = new Scanner(System.in);
System.out.println("请输入年份");
year = sc.nextInt();
System.out.println("请输入月份");
month = sc.nextInt();
System.out.println("请输入日期");
date = sc.nextInt();
switch (month) {
case 12:
dayNumber = dayNumber + 30;
case 11:
dayNumber = dayNumber + 31;
case 10:
dayNumber = dayNumber + 30;
case 9:
dayNumber = dayNumber + 31;
case 8:
dayNumber = dayNumber + 31;
case 7:
dayNumber = dayNumber + 30;
case 6:
dayNumber = dayNumber + 31;
case 5:
dayNumber = dayNumber + 30;
case 4:
dayNumber = dayNumber + 31;
case 3:
dayNumber = dayNumber + 28;
case 2:
dayNumber = dayNumber + 31;
case 1:
dayNumber = dayNumber + 0;
}
dayNumber = dayNumber + date;
// 如果是闰年,且月份晚于2月,则多加1天
if ((year % 100 != 0 && year % 4 == 0 || year % 400 == 0) && month >= 3) {
dayNumber = dayNumber + 1;
}
System.out.println(month + "月" + date + "日在" + year + "年是" + dayNumber + "天");
}
}
选择输入一个闰年2020年验证程序,可以看到运行结果如图2-20所示。
图2-20 【例02_13】运行结果
此处还需强调:本例题中并没有对输入的年月日数值的合理性做判断,例如输入2月30日程序也不不会提示用户输入有误,读者可自行补充相关代码。
除此文字版教程外,小伙伴们还可以点击这里观看我在本站的视频课程学习Java。