2.3 “简易日历表”实例
【实例说明】
本实例是在一个页面上输出1900年以后任意一年的简易日历表,程序运行界面如图2.3所示。
图2.3 程序输出结果
【实例目的】
(1)学习并掌握简单if语句和嵌套if语句在多分支结构中的用法。
(2)学习并掌握for语句在固定次数循环中的用法。
(3)学习并掌握while语句在循环结构中的用法。
(4)学习并掌握do−while语句在循环结构中的用法。
(5)学习并了解break语句、continue语句等跳转语句。
(6)学会有关日历表的相关计算方法。
(7)学习并掌握简单循环和多重循环结构程序开发的一般步骤和方法。
【技术要点】
1)自1990年之后,“每年的1月1日是星期几”的求解方案
(1)给定1900年1月1日是星期一。
(2)若某一年的总天数为365天,将其除以7,得余数为1,则下一年1月1日的星期为当年1月1日的星期加1;若某一年的总天数为366天(即闰年),将其除以7,得余数为2,则下一年1月1日的星期为上一年1月1日的星期加2。例如,1999年的1月1日为星期五,则2000年的1月1日为星期六,而2001年的1月1日为星期一,因为2000年为闰年。
例如,案例中相应的程序段如下:
2)“每个月的1日是星期几”的求解方案
(1)首先计算当年1月1日对应的星期。
(2)从2月开始,每月的1日对应的星期应为其上月1日的星期和上月的总天数之和除以7的余数。例如,2008年1月1日为星期二,则2月1日应为(2+31)%7=5,即星期五。
【相关知识及注意事项】
2.3.1 程序的控制结构
在编写程序时,我们往往会遇到由一个语句块跳转到另一个语句块的情况。如果没有流程控制语句,编写的程序只能按照顺序执行。Java语言提供了三种类型的流程控制结构:
● 选择结构:if−else,switch。
● 循环结构:while,do−while,for。
● 与程序转移有关的跳转语句:break,continue,return。
2.3.2 选择结构
在现实生活中,事务处理的过程不是简单地从开始到结束的顺序过程,中间可能会根据具体情况的不同进行不同的操作,这就是选择(也称为分支或条件)。程序语言中的选择结构就是为了适应现实生活中的各种各样的判断而提出的,选择结构可以根据某些表达式的值有选择地执行特定的语句。Java语言主要提供了if语句和switch语句两种选择结构。
1.if语句
if语句,也称为条件语句,是根据给定条件进行判定,以决定执行某个分支程序段。Java中的if语句有两种形式。
(1)if语句
if语句的语法格式如下:
例如,案例中如下程序段:
if(i%7==0)
System.out.print(" "); //每行中月份之间的空格
其中:
● 布尔表达式一般为关系表达式或逻辑表达式,其值为true或false。
● 语句块1可以是单条语句,也可以是复合语句。
● if语句的执行过程为:若布尔表达式值为真,则执行语句块1;否则,不执行该语句块,而执行if语句的后续语句,如图2.4所示。
(2)if−else语句
if−else语句的语法格式如下:
例如,案例中如下程序段:
其中:
● 布尔表达式一般为关系表达式或逻辑表达式,其值为true或false。
● []所括的else子句部分是可选的,它必须和if成对出现。
● 语句块1和语句块2可以是单条语句,也可以是复合语句。
● if−else语句的执行过程为:若布尔表达式值为真,则执行语句1;否则执行语句2,如图2.5所示。
if语句的嵌套。现实生活中的条件往往并不单一,在一定的条件下,又需要满足其他的条件才能确定相应的操作。为此,Java提供了if语句的嵌套功能,即一个if语句能够出现在另一个if语句或if-else语句里。if语句的嵌套语法格式如下:
图2.5 if-else语句执行过程
例如,案例中如下程序段:
表示的含义是:如果表达式1为真,执行语句块1;否则对表达式2进行判断,如果表达式2为真,则执行语句块2;否则继续判断,直至某个表达式为真就执行对应的语句。如果所有表达式均为假,则执行语句块n+1。if嵌套语句的执行过程如图2.6所示。
图2.6 嵌套if语句执行过程
2.switch语句
对于多选择分支的情况,可以用if语句的if−else形式或if语句嵌套处理,但大多数情况下显得比较麻烦。为此,Java提供了另一种多分支选择结构—switch语句。
switch语句的一般形式如下:
例如,案例中如下程序段:
其中:
(1)switch语句表达式的值和case子句中的常量值的类型必须一致。
表达式的值支持int类型相容的数据类型,即byte、short、char和int四种类型。Java7之后,switch语句控制表达式的值也支持字符串,例如下列程序代码:
以上代码中case子句中的常量值为字符串,这在Java7之前并不支持,但是Java7以后都可以这样使用了。
(2)各case子句中的常量值不能相同。
(3)语句可以是单条语句,也可以是复合语句。
switch语句的执行过程如下:首先对switch后面圆括号内表达式的值进行计算,然后从上至下找出与表达式的值相匹配的case,以此作为入口,执行switch结构中后面的各语句块。若表达式的值与任何case均不匹配,则执行default后面的语句块。如果没有default部分,将不执行switch语句中的任何语句块,而直接转到switch语句后的语句执行。
使用switch语句,应注意以下几个问题:
(1)default子句及其后的语句块n+l可以省略。
(2)case子句和default子句出现的次序是任意的,也就是说,default子句也可以位于case子句的前面,且case子句的次序也不要求按常量值的顺序排列。
(3)case子句只起到一个标号的作用,用来查找匹配的入口,并从此开始执行其后面的语句块,对后面的case子句不再进行匹配。因此,在每个case分支后,用break语句来终止后面的case分支语句的执行。有一些特殊情况,如多个不同的case值要执行一组相同的语句块,在这种情况下,可以不用break语句。
处理多分支情况时,用switch语句代替if语句可以简化程序,使程序结构清晰明了,增强可读性。
2.3.3 循环控制结构
循环结构是指在满足一定条件的前提下,某些语句或操作可以重复执行的处理结构。程序中循环结构有三种:while语句、do−while语句和for语句。循环结构中,程序流程从循环的开始到循环的结束都依赖于循环的控制条件判断。在每次循环时都需要对循环控制的布尔表达式运算,由这个表达式的值来确定循环是继续还是结束。循环流程总是在控制条件判断的值为true时,循环得以继续,控制条件判断的值为false时循环结束。
在循环的结构中,循环是由四个部分组成,根据不同的循环语句,它们之间执行顺序有所不同,这四个组成部分是:
● 初始化部分(initalization):为循环设置初始量;
● 判断部分(condition):布尔表达式,其值决定循环是否继续;
● 循环体部分(body):循环的代码段(语句);
● 迭代部分(iteration):每循环一次,改变循环控制变量的值。
1.while语句
while语句的语法格式如下:
while语句的执行过程如下:首先计算表达式的值,若表达式的值为true,执行循环体语句块,然后再次计算表达式的值,重复上述过程,直到表达式的值为false,则退出循环。
例如:本案例中输出星期提示列表,程序段如下所示。
while语句的特点是:先计算表达式的值,然后执行语句,因此当表达式的值一开始就为false时,循环体将一次也不执行。程序执行流程图如图2.7所示。
图2.7 while循环结构流程图
使用while语句时,应注意以下几个问题:
(1)语句可以是单条语句,也可以是复合语句。
(2)为了避免产生“死循环”,循环控制变量要动态变化或在循环体中有使循环趋向于结束的语句。
2.do−while语句
do−while语句的一般格式如下:
do−while语句的执行过程如下:首先执行作为循环体的语句,然后再计算表达式的值,当表达式的值为true时,再执行循环体中的语句,重复上述过程,直到表达式的值为false时,结束循环。
例如,本案例中输出星期提示列表的while循环结构也可以改写为do−while循环结构,程序段如下所示。
do−while语句的特点是:先执行循环体中的语句,然后再计算表达式的值,因此即使一开始条件就不成立,循环体也执行一次。使用do−while语句时,应注意结尾处while(布尔表达式)后的分号不能省略。程序执行流程图如图2.8所示。
图2.8 do−while循环结构流程图
3.for语句
for语句的一般格式如下:
表达式1通常用于变量的初始化,表达式2是一个布尔表达式,一般用来判断循环是否继续执行,表达式3通常用于更新循环控制变量的值。循环体语句块是for语句重复执行的部分。
例如,案例中求解1900年后的任一年(如2013年)的1月1日是星期几的程序段如下:
for语句的执行过程如下:
(1)求解表达式1。
(2)求解表达式2,若表达式2的值为true,执行语句;若表达式2的值为false,则退出循环。当表达式2的值一开始就为false时,循环体将一次也不执行。
(3)求解表达式3,转(2),如图2.9所示。
使用for语句时,应注意以下几个问题:
(1)循环体语句块可以是单条语句,也可以是复合语句。
(2)表达式1、表达式2和表达式3都可以省略,但作为分隔符的分号一定要保留。当省略表达式2时,相当于无限循环(循环条件总为true),这时就需要在for语句的循环体中设置相应的语句,以结束循环。
(3)for语句中的表达式1和表达式3可以是简单表达式,也可以是逗号表达式。
图2.9 for循环结构流程图
2.3.4 break和continue语句
1.break语句
break语句在switch语句中,用于终止switch语句的执行,使程序跳出switch语句块转而从switch语句的下一语句开始执行。
break语句的另一种使用情况就是跳出它所指定的块,并从紧跟该块的第一条语句处执行。break语句的语法格式为:
break [标号];
break语句有两种形式:不带标号和带标号。标号是一个标识符,用于给程序块起一个名字。标号必须位于break语句所在的封闭语句的开始处。
不带标号的break语句只能终止包含它的最小程序块,有时希望终止更外层的块,可使用带标号的break语句,它使得程序流程转到标号指定语句块的后面执行。
例如,可以通过不带标号的break语句终止循环,来实现1901-2008年之间任意一年的1月1日是星期几的求解,参考程序段如下:
2.continue语句
continue语句只用于循环结构中,它的语法格式为:
continue [标号];
不带标号的continue语句的作用是终止当前循环结构的本轮循环,直接开始下一轮循环;带标号的continue语句的作用是把程序直接转到标号所指定的代码段的下一轮循环。
注意:Java中没有像C或C++中那样的goto语句,标号就相当于是一种goto语句。但是,就像C/C++中使用goto会破坏代码的可读性一样,在Java中使用标号也会影响代码的结构性。我们通常是建议尽可能避免使用标签,一定要用时务必要谨而慎之。
【代码及分析】
程序解释及常见问题如下:
(1)“boolean leap=year%4==0&&year%100!=0||year%400==0;”语句的作用是判断当年是否是闰年,其判断依据是:“四年一闰,百年不闰,四百年又闰。”
(2)“System.out.print(spa1--<=0&&day1<=cou1?day1<10?"0"+day1++:""+day1++:"");”语句的作用是:要使得每月1日与星期相对应地显示在屏幕上,就得在开始前加若干个空格,空格数由此月1日的星期决定。在显示时,每个月的天数不能超过其总天数,所有超过部分都应用空格代替。另外,所有的日期数字均以两位数的方式显示,故需要在一位的数字前加0。
语句的执行过程为:如果“spa1--<=0&&day1<=cou1”表达式的值为真,就计算“day1<10?"0"+day1++:""+day1++”表达式,此表达式是一个三目运算,须继续判断。如果“day1<10”表达式为真,计算“"0"+day1++”表达式,否则计算“""+day1++”表达式。此语句相当于以下的程序段:
【应用扩展】
程序是在一个页面上显示某一年的12个月,也可以利用下拉式菜单有选择地进行显示,并且在一个页面上只显示一个月份的信息。