分支结构
什么是分支结构
首先,看一个需求,假设需要编写一个收银柜台收款程序,要求根据商品单价、购买数量以及收款金额,计算并输出应收金额和找零。
通过分析可以想到,这个程序,需要定义三个输入,即:单价、数量、金额。定义两个输出,即:应收金额、找零。因为金额有可能为小数类型,所以变量的数据结构定义为double类型。
此程序可以以如下方式解决,用户由控制台输入:商品单价、购买数量、收款金额;而后计算商品的总价及找零,并输出。示例代码如下所示:
- public static void main(String[] args) {
- //定义输入
- Scanner console = new Scanner(System.in);
- System.out.println("请输入单价(¥):");
- double unitPrice = console.nextDouble();
- System.out.println("请输入数量:");
- double amount = console.nextDouble();
- System.out.println("请输入金额(¥):");
- double money = console.nextDouble();
- console.close();
-
- //计算商品总价
- double totalPrice = unitPrice * amount;
- //计算找零
- double change = money - totalPrice;
-
- //输出
- System.out.println("应收金额为:" + totalPrice +",找零为:" + change);
- }
如上代码,输入数据后,可以正确输出应收金额及找零,假设现在需求增加,当商品总价满500时享受8折优惠, 如何解决?这种情况,在软件应用中,需要使用分支结构来实现。
任何复杂的程序逻辑结构都可以通过“顺序”,“分支”,“循环”这三种基本的程序结构实现。如图 – 1所示:
图- 1
刚刚的案例即为顺序结构,第一步A执行完执行第二步B,第二步执行完执行第三步,一步一步顺序执行。分支结构即为根据一个条件做判断,如果条件满足则执行A,否则执行B。还有一种即为后面要介绍的循环结构。原则上,任何复杂的程序, 都可以通过这三种结构来解决。
当程序在运行过程中, 需要根据不同的条件而运行不同的语句时,即可以使用分支结构,Java中有专门的语法结构来实现分支:
- 当条件满足时运行某些语句;当条件不满足时则不运行这些语句——if结构。
- 当条件满足时运行某些语句; 当条件不满足时运行另外一些语句——if-else结构
if语句
if语句的执行逻辑
首先看下面if语句的语法:
- 语句0;
- if(逻辑表达式){
- 语句1;
- 语句2;
- }
- 语句3;
如上语句的执行步骤如下所示:
步骤一:执行语句0;
步骤二: 判断逻辑表达式的值,此表达式的值结果为boolean类型,即true或者false。此处可以是关系表达式也可以是逻辑表达式。
- 若值为true,则执行if语句块中的语句;
- 若值为false,则跳过if语句块;
步骤三:执行语句3语句。
if语句流程图
if语句的执行逻辑如下图 - 2所示:
图- 2
通过图示得出结论:当条件满足时,执行语句块,然后执行if语句下面的语句;否则跳过语句块,直接执行if语句下面的语句。
if语句用于处理分支逻辑
if语句是java中用于处理分支结构的语句,下面,通过if语句来实现刚刚的打折功能逻辑,再回顾一下新添的需求:如果商品总价大于等于500,则打8折。如下图– 3 红色部分即为if的判断逻辑:
图- 3
可以看到,计算商品总价之后,进行了总价大于等于500的业务判断,若判断结果为true,则计算折扣后的应收金额,再计算找零后输出。若判断结果为false,则直接计算找零后输出。如下即为实现代码:
- ……
- double totalPrice = ……;
- if (totalPrice >= 500) {
- totalPrice = totalPrice * 0.8;
- }
- ……
通过如上代码可以看出: 当total>=500为true时, 总额乘以0.8, 即打8折。当total>=500为false时,不执行if语句块的内容。
if语句块不要省略“{}”
if语句块在执行过程中,有一个问题是需要注意的,先看下面的两段代码:
- 代码一:
- int num = 5;
- if(num>2)
- System.out.print(num);
- System.out.println(“ 大于2 ”);
- 代码二:
- int num = 5;
- if(num>2){
- System.out.print(num);
- System.out.println(“ 大于2 ”);}
分析如上两个代码段,得出的结论是:两段代码输出结果一样,即 “5 大于 2”。再看如下两段代码,输出结果还一样吗?
- 代码一:
- int num = 5;
- if(num<2)
- System.out.println(num);
- System.out.println(“小于2”);
- 代码二:
- int num = 5;
- if(num<2){
- System.out.print(num);
- System.out.println(“小于2”);}
分析如上两个代码段,可以得出,代码段一的输出结果是“大于2”,代码段二没有任何输出。分析输出结果可以看出,代码段二的结果为正确结果,而代码段一输出的“小于2”是不应该存在的,出现这个问题的原因在于,在if语句之后没有添加“{}”,而java语法规定,当if语句块中只包含一条语句时,可以省略“{}”,但是if语句块也只能作用于它下面的一条语句。
看如上代码段一的if判断,只作用于第一个输出语句,因为num<2结果为false,所以第一个输出语句并未执行,而第二个输出语句“小于2”不属于if作用范围,所以无论条件满足与否,都会执行。故而,输出了“小于2”的结果。
所以,考虑到代码的可读性、扩展性,建议即便if语句块中只有一条语句,也不要省略“{}”。
if-else语句
if-else语句的执行逻辑
分析上面的案例,当计算出最终(打折前、打折后)的应收金额后,直接计算找零,这
个时候就出现了一个问题,如果收款的金额小于应收的金额,那么输出的找零就会为负数结果,这显然用户体验不好,下面对它做一下改进,要求考虑程序的异常情况,增加需求如下:
- 若收款金额大于等于应收金额,则计算找零后输出;
- 若收款金额小于应收金额,则输出错误提示信息,如何处理?
这种情况,单单使用if语句显然无法解决了,因为if语句用于解决的是,当某条件满足时执行某段业务处理的逻辑,而现在的逻辑时,当条件满足时执行某段业务逻辑,当条件不满足时需要执行另一段业务逻辑。看如下图 – 4所示的红色部分:
图- 4
若想实现这样的判断逻辑,可以考虑if-else语句。看一下下面的语法:
- 语句0;
- if(逻辑表达式){
- 语句块1;
- } else {
- 语句块2;
- }
- 语句3;
如上语句的执行步骤如下所示:
步骤一:执行语句0;
步骤二:判断if逻辑表达式的值:
- 若值为true,则执行语句块1;
- 若值为false,则执行语句块2;
步骤三:执行语句3语句。
if-else语句流程图
if-else语句的执行逻辑如下图 - 5所示:
图- 5
通过图-5可以看到:当条件满足时,执行语句块1,然后执行if-else语句下面的语句;否则执行语句块2,再执行if-else语句下面的语句。
if-else语句用于处理分支逻辑
通过下面的代码,可以解决新增加的异常情况处理问题:
- ……
- if( money >= totalPrice ) { double change = money – totalPrice;
- System.out.println("应收金额为:" + totalPrice +",找零为:" + change);
- } else { System.out.println(“Error! 收款金额小于应收金额”);
- }
说明:money为收款金额,totalPrice为应收金额;当收款金额大于等于应收金额时,则计算找零并输出,否则,提示错误信息。
else if语句
if-else语句的嵌套
在日常生活中,很多情况并非进行一次逻辑判断就可以获取最终的结果, 如图– 6所示:
图 - 6
可以看出,实现制作沙拉的过程进行了两次判断,首先判断是否有黄瓜,若有则直接制作黄瓜沙拉后结束,若没有黄瓜则判断是否有胡萝卜,若有则制作胡萝卜沙拉结束,没有则不能上菜结束。这种情况,单单使用if-else还无法实现,因为if-else只是判断了一次就结束了,而当前的情况需要判断两次。
在java程序中,当程序的分支数大于2时,可以用if-else嵌套的方式解决,即:else语句块中又包含if语句(或if-else语句),下面看一个实际的需求:
根据学员的成绩来输出等级:
- A(成绩大于等于90分);
- B(成绩小于90分且大于等于80分);
- C(成绩小于80分且大于等于60分);
- D(成绩小于60)。
此程序即为多路判断,如图– 7所示流程图:
图- 7
首先判断分数是否大于等于90,若为真则输出A终止,为假则再判断分数是否大于等于80,若为真输出B终止,为假则再判断分数是否大于等于60,若为真输出C终止,为假则输出D。分析可以看出,该程序经过了3次判断。需要在else中嵌套判断。代码如下所示:
else if语句执行逻辑
如下图 – 8所示,在else中再次进行if-else的判断:
图- 8
从上图中看出,当判断层数比较多时,代码清晰度不够好,在实际开发中常常使用如下图- 9的方式来实现,事实上,else if结束就是if-else嵌套的简便写法:
图 – 9
实现该程序代码如下所示:
- … … ...
- if(score>=90) {
- System.out.println("A");
- } else if (score>=80) {
- System.out.println("B");
- } else if(score>=60) {
- System.out.println("C");
- } else {
- System.out.println("D");
- }
通过上面的代码可以看出,使用else if方式,程序逻辑更清晰,可读性更好。
switch-case语句
switch-case语句执行逻辑
switch-case是一种特殊的分支结构,与else if类似,但其应用面不如else if,只能用于特殊的情况之下, switch-case可以根据一个整数值的不同取值,从不同的程序入口开始执行。语法如下所示:
- switch(整型表达式) {
- case 整型常量值1: //入口1
- 语句1;
- 语句2;
- case 整型常量值2: //入口2
- 语句3;
- ……
- default: //默认入口
- 语句n;
- }
switch-case流程图见图 – 10所示:
图- 10
分析上图,可以看出其执行逻辑如下:
计算整型表达式的值:
- 若值等于整型常量值1,则从语句1开始执行,而后语句2、3,一直执行到语句n。
- 若值等于整型常量值2,则从语句3开始执行,一直执行到语句n。
- 若没有找到匹配的值,则只执行语句n。
通过分析可以看出,switch是以case后的整型常量值作为入口的,若值相等,即开始执行其后面的语句。
使用switch时需要注意两个问题,第一,case后面的常量值必须不同,第二,switch后面的整型表达式的值必须是整型或字符型。
switch-case和break联合使用
前面的代码中判断整型表达式的值,若其值等于某个整型常量值,则会以此作为入口,依次执行其后面所有的语句。但是在实际应用中,通常case1、case2、…、caseN对应完全不同的操作,即: 若表达式的值等于case1,则只执行case1后的语句,不会再执行case2、caseN等后面的语句。这种情况下可以和break语句配合使用,执行完相应语句后即退出switch块,不继续执行下面的语句。语法如下所示:
- switch(整型表达式) {
- case 整型常量值1: //入口1
- 语句1;
- 语句2;
- break ;
- case 整型常量值2: //入口2
- 语句3;
- break ;
- ……
- default: //默认入口
- 语句n;
- }
如上程序中的break语句的作用在于跳出switch结构,其执行逻辑如下:
- 计算整型表达式的值:
- 如果值等于整型常量值1,则执行语句1、语句2,跳出switch结构结束;
- 若值等于整型常量值2,则执行语句3,跳出switch结构结束;
- 如果没有找到匹配的值,则执行语句n,结束。default后可以不写break。
switch-case语句用于分支
在实际应用中,switch-case语句常常与break配合使用,参见下面的代码:
- int num = 2;
- switch(num) {
- case 1:
- System.out.println(“呼叫教学部”);
- break;
- case 2:
- System.out.println(“呼叫人事部”);
- break;
- default:
- System.out.println(“人工服务”);
- }
上面代码的输出结果为“呼叫人事部“,因为匹配case 2输出后,即break跳出switch语句了。
switch-case的优势
switch-case结构在实际应用中较广泛, 常常和break语句结合使用实现分支的功能。
在很多情况下,switch-case可以代替else if结构,而switch-case实现分支功能的效率要高于else if结构,并且结构更清晰,所以推荐使用。从JDK 7.0开始,switch-case可以支持字符串表达式,将更加方便程序的操作。
循环结构(while,do…while)
什么是循环结构
在日常生活中,会有很多需要反复执行的事情,比如:每一年的4个季节,每一周的7天,每日的3餐,打印机每份文档打印50份,一圈跑道400米跑3圈,都是在反复执行的。
再看软件系统中的需求:
问题1:输出100行语句,每行语句都一样,即:
- 行动是成功的阶梯,行动越多,登得越高!
- 行动是成功的阶梯,行动越多,登得越高!
- 行动是成功的阶梯,行动越多,登得越高!
…
问题2:输出100行语句,每行语句都类似,即:
- 第1,行动是成功的阶梯,行动越多,登得越高!
- 第2,行动是成功的阶梯,行动越多,登得越高!
- 第3,行动是成功的阶梯,行动越多,登得越高!
- …
- 第100,行动是成功的阶梯,行动越多,登得越高!
问题3:计算1到50乘以8.88的结果
- 1× 8.88 =8.88
- 2 × 8.88 =17.76
- 3 × 8.88 =26.64
- 4 × 8.88 =35.52
- …
- 50 × 8.88 =444
诸如此类问题都是在反复执行的,在软件系统中可以通过循环这种语法结构来解决。循环是程序设计语言中反复执行某些代码的一种计算机处理过程, 是一组相同或相似语句被有规律的重复性执行。
对于循环来说,需要考虑两个要素,其一要素为循环体, 也就是被反复执行的相同或相似的语句,其二要素为循环的条件,也就是循环得以继续执行下去的条件,常常以循环次数的方式体现。
常用的循环结构有:while、do-while、for。今天介绍while、do-while。
while语句
while语句的执行逻辑
while语句是循环的一种常见语法结构,语法如下:
- while( boolean表达式 ) { 语句块;
- }
while语句的执行过程为,首先计算boolean表达式的值,而后进行判断,若值为true则执行语句块,语句块执行完后再次判断boolean表达式的值,如果为true则继续执行语句块,如此循环往复,直到boolean表达式的值为false时退出while循环而执行while之后的语句。
while语句的流程图
while语句的流程图如图 - 11所示,需要注意的是,一般情况下,循环操作中会存在使得循环条件不满足的可能性,否则该循环将成为“死循环”。“死循环”意味着会一直执行循环体操作,循环后面的语句永远不会被执行,“死循环”在软件系统中是需要避免的。
图 - 11
while语句用于处理循环逻辑
while语句在实际应用中应用比较广泛,通过如下示例体会while语句的执行逻辑:
- int age = 1;
- while (age<=100) {
- System.out.println(“马上有钱”);
- age++;
- }
上面的语句执行过程如下,首先声明整型变量age并赋初始值为1,而后判断age是否小于等于100,条件为真,输出“马上有钱”并将age的值增1变为2,再次判断条件,此时age为2,依然小于100,再一次输出“马上有钱”并将age的值再增1变为3,以此类推,直到age等于101时,判断条件为false,循环结束。
使用break语句跳出循环
break用在循环体中用于退出循环结构。看如下示例代码:
- int x = 0;
- while ( x < 10 ) {
- if ( 5 == x )
- {
- break;
- }
- System.out.println(x);
- x + + ;
- }
分析上面的代码得出结论,输出结果为0 1 2 3 4,因为当x等于5时执行break语句直接退出循环结构了,即if语句块后面的输出x的值以及x++不再被执行。
do-while语句
do-while语句的执行逻辑
do-while语句也是循环的一种常见语法结构,语法如下:
- do {
- 语句块
- } while( boolean表达式 ) ;
do-while语句的执行过程为,先执行语句块,再判断boolean表达式,如果为true则再次执行语句块,如此循环往复,直到boolean表达式的值为false时止。也就是说,do-while语句,无论boolean表达式是否为true,都先执行一次语句块。
do-while语句的流程图
do-while语句的流程图如图 - 12所示,与while语句一样,do-while语句也要避免“死循环”的发生。
图- 12
do-while语句用于处理循环逻辑
do-while语句在实际应用中应用比较广泛, 通过如下示例体会do-while语句的执行逻辑:
- int pwd ;
- do{
- System.out.print(“请输入密码”);
- pwd = scanner.nextInt();
- } while ( 123 != pwd) ;
上面的语句执行过程如下,首先声明整型变量pwd,在do语句中提示“请输入密码”,接收用户输入的数据赋给pwd, 而后判断123是否不等于pwd,若为true则执行do语句块,以此类推,直到123等于pwd时,循环结束。
while和do-while语句的区别
while与do-while都是用于执行循环结构的语句,区别在于,while循环先判断再执行,而do-while循环先执行一次,再判断。那么,当初始情况不满足循环条件时,while循环就一次都不会执行,而do-while循环不管任何情况都至少会执行一次。
注意:while和do-while语句的不同仅仅体现在第一次就不满足条件的循环中;如果不是这样的情况,while与do-while可以互换。请看如下两段示例程序:
- 示例1:while循环方式
- int pwd = 0;
- while ( 123 != pwd){
- System.out.print(“密码:”);
- pwd = scanner.nextInt();
- }
- 示例2: do-while循环方式
- int pwd ;
- do{
- System.out.print(“密码”);
- pwd = scanner.nextInt();
- } while ( 123 != pwd) ;
分析示例1与示例2得出结论,运行结果完全一样。这是因为两段代码第一次的while条件都满足,此时while与do-whlie可以互换,所以结果完全一样。