第四章 流程控制语句
一、概述
1.1、说明
在一个程序执行的过程中,各条语句的执行顺序对程序的结果是有直接影响的。也就是说,程序的流程对运行结果有直接的影响。所以,我们必须清楚每条语句的执行流程。而且,很多时候我们要通过控制语句的执行顺序来实现我们要完成的功能。
简单来说:流程控制语句是用来控制程序中各语句执行顺序的语句,可以把语句组合成能完成一定功能的小逻辑模块。
1.2、分类
- 顺序结构
- 分支结构/选择结构
- if
- switch
- 循环结构
- for
- while
- do...while
二、顺序结构
2.1、说明
顺序结构是程序中最简单最基本的流程控制,没有特定的语法结构,按照代码的先后顺序,依次执行。
2.2、案例
public static void main(String[] args){
//顺序执行,根据编写的顺序,从上到下运行
System.out.println(1);
System.out.println(2);
System.out.println(3);
}
三、分支结构
3.1、if 语句
3.1.1、场景引入
if
语句是指如果满足某种条件,就进行某种处理。
例如,小明妈妈跟小明说“如果你考试得了100分,星期天就带你去游乐场玩”。这句话可以通过下面的一段伪代码来描述。
如果小明考试得了100分
妈妈星期天带小明去游乐场
在上面的伪代码中,“如果”相当于Java中的关键字if,“小明考试得了100分”是判断条件,需要用()括起来,“妈妈星期天带小明去游乐场”是执行语句,需要放在{}中。修改后的伪代码如下:
if (小明考试得了100分) {
妈妈星期天带小明去游乐场
}
3.1.2、语法格式
if (条件表达式){
语句体;
}
执行流程:
① 首先计算条件表达式的值
② 如果关系表达式的值为true就执行语句体
③ 如果关系表达式的值为false就不执行语句体
④ 继续执行后面的语句内容
3.1.3、案例
public static void main(String[] args) {
System.out.println("开始");
//定义两个变量
int a = 10;
int b = 20;
//需求:判断a和b的值是否相等,如果相等,就在控制台输出:a等于b
if(a == b) {
System.out.println("a等于b");
}
//需求:判断a和c的值是否相等,如果相等,就在控制台输出:a等于c
int c = 10;
if(a == c) {
System.out.println("a等于c");
}
System.out.println("结束");
}
3.2、if…else语句
3.2.1、说明
if…else
语句是指如果满足某种条件,就进行某种处理,否则就进行另一种处理。
例如,要判断一个正整数的奇偶,如果该数字能被2整除则是一个偶数,否则该数字就是一个奇数。
3.2.2、语法格式
if(关系表达式) {
语句体1;
}
else {
语句体2;
}
执行流程:
① 首先计算关系表达式的值
② 如果关系表达式的值为true就执行语句体1
③ 如果关系表达式的值为false就执行语句体2
④ 继续执行后面的语句内容
3.2.3、案例
public static void main(String[] args) {
int num = 19;
if (num % 2 == 0) {
// 判断条件成立,num被2整除
System.out.println("num是一个偶数");
} else {
System.out.println("num是一个奇数");
}
}
3.3、if…else if…else语句
3.3.1、说明
if…else if…else语句用于对多个条件进行判断,进行多种不同的处理。
例如,对一个学生的考试成绩进行等级的划分,如果分数大于80分等级为优,否则,如果分数大于70分等级为良,否则,如果分数大于60分等级为中,否则,等级为差。
3.3.2、语法格式
if (关系表达式1) {
语句体1;
}
else if (关系表达式2) {
语句体2;
}
...
else if (关系表达式n) {
语句体n;
}
else {
语句体n+1;
}
执行流程:
① 首先计算关系表达式1的值
② 如果值为true就执行语句体1;如果值为false就计算关系表达式2的值
③ 如果值为true就执行语句体2;如果值为false就计算关系表达式3的值
④ …
⑤ 如果没有任何关系表达式为true,就执行语句体n+1。
3.3.3、案例
public static void main(String[] args) {
int grade = 75; // 定义学生成绩
if (grade > 80) {
// 满足条件 grade > 80
System.out.println("该成绩的等级为优");
} else if (grade > 70) {
// 不满足条件 grade > 80 ,但满足条件 grade > 70
System.out.println("该成绩的等级为良");
} else if (grade > 60) {
// 不满足条件 grade > 70 ,但满足条件 grade > 60
System.out.println("该成绩的等级为中");
} else {
// 不满足条件 grade > 60
System.out.println("该成绩的等级为差");
}
}
3.3.4、案例2
需求:键盘录入一个星期数(1,2,...7),输出对应的星期一,星期二,...星期日。
public static void main(String[] args) {
System.out.println("开始");
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个星期数(1-7):");
int week = sc.nextInt();
if(week == 1) {
System.out.println("星期一");
}else if(week == 2) {
System.out.println("星期二");
}else if(week == 3) {
System.out.println("星期三");
}else if(week == 4) {
System.out.println("星期四");
}else if(week == 5) {
System.out.println("星期五");
}else if(week == 6) {
System.out.println("星期六");
}else {
System.out.println("星期日");
}
System.out.println("结束");
}
3.4、选择结构if语句与三元运算转换
3.4.1、说明
有时候,三元运算符和选择结构if语句可以转换。
3.4.2、案例
需求:例如求两个数x、y中的较大者,如果用if…else语句来实现,具体代码如下:
public static void main(String[] args){
int x = 0;
int y = 1;
int max;
if (x > y) {
max = x;
} else {
max = y;
}
}
上面的代码运行之后,变量max的值为1。其中,if...else语句可以用三元运算符代替:
public static void main(String[] args){
int x = 0;
int y = 1;
int max = x > y ? x : y;
}
3.5、switch 语句
3.5.1、场景引入
switch 条件语句也是一种很常用的选择语句,它和if条件语句不同,它只能针对某个表达式的值作出判断,从而决定程序执行哪一段代码。
例如,在程序中使用数字1~7来表示星期一到星期天,如果想根据某个输入的数字来输出对应中文格式的星期值,可以通过下面的一段伪代码来描述:
用于表示星期的数字
如果等于1,则输出星期一
如果等于2,则输出星期二
如果等于3,则输出星期三
如果等于4,则输出星期四
如果等于5,则输出星期五
如果等于6,则输出星期六
如果等于7,则输出星期天
对于上面一段伪代码的描述,大家可能会立刻想到用刚学过得if…else if…else语句来实现,但是由于判断条件比较多,实现起来代码过长,不便于阅读。Java中提供了一种switch语句来实现这种需求,在switch语句中使用switch关键字来描述一个表达式,使用case关键字来描述和表达式结果比较的目标值,当表达式的值和某个目标值匹配时,会执行对应case下的语句。具体实现代码如下:
switch(用于表示星期的数字) {
case 1 :
输出星期一;
break;
case 2 :
输出星期二;
break;
case 3 :
输出星期三
break;
case 4 :
输出星期四;
break;
case 5 :
输出星期五;
break;
case 6:
输出星期六;
break;
case 7:
输出星期天;
break;
}
3.5.2、语法格式
switch(表达式) {
case 常量值1:
语句体1;
break;
case 常量值2:
语句体2;
break;
...
default:
语句体n+1;
break;
}
执行流程:
① 首先计算出表达式的值
② 其次,和case依次比较,一旦有对应的值,就会执行相应的语句,在执行的过程中,遇到break就会结束。
③ 最后,如果所有的case都和表达式的值不匹配,就会执行default语句体部分,然后程序结束掉。
3.5.3、案例1
public static void main(String[] args) {
//定义变量,判断是星期几
int weekday = 6;
//switch语句实现选择
switch(weekday) {
case 1:
System.out.println("星期一");
break;
case 2:
System.out.println("星期二");
break;
case 3:
System.out.println("星期三");
break;
case 4:
System.out.println("星期四");
break;
case 5:
System.out.println("星期五");
break;
case 6:
System.out.println("星期六");
break;
case 7:
System.out.println("星期日");
break;
default:
System.out.println("你输入的数字有误");
break;
}
}
3.5.4、case穿透
在switch语句中,如果case的后面不写break,将出现穿透现象,也就是不会在判断下一个case的值,直接向后运行,直到遇到break,或者整体switch结束。
public static void main(String[] args) {
int i = 5;
switch (i){
case 0:
System.out.println("执行case0");
break;
case 5:
System.out.println("执行case5");
case 10:
System.out.println("执行case10");
default:
System.out.println("执行default");
}
}
上述程序中,执行case 5后,由于没有break语句,程序会一直向后走,不会在判断case,也不会理会break,直接运行完整体switch。
3.5.5、案例2
有时候,可以利用case穿透,反而解决程序的书写。
public static void main(String[] args) {
int week = 2;
switch (week) {
case 1:
case 2:
case 3:
case 4:
case 5:
// 当 week 满足值 1、2、3、4、5 中任意一个时,处理方式相同
System.out.println("今天是工作日");
break;
case 6:
case 7:
// 当 week 满足值 6、7 中任意一个时,处理方式相同
System.out.println("今天是休息日");
break;
}
}
}
public static void main(String[] args){
int month = 6;
switch(month){
case 12:
case 1:
case 2:
System.out.println("冬季");
break;
case 3:
case 4:
case 5:
System.out.println("春季");
break;
case 6:
case 7:
case 8:
System.out.println("夏季");
break;
case 9:
case 10:
case 11:
System.out.println("秋季");
break;
}
}
3.5.6、特别注意
# switch结构中的表达式,只能是如下的六种数据类型之一:byte、short、char、int、枚举类型(JDK5.0)、String类型(JDK7.0)
# 不能是:long,float,double,boolean。
3.5.7、Java12之后switch新特性(选讲)
Switch 表达式也是作为预览语言功能的第一个语言改动被引入Java12 中,开始支持如下写法:
switch(month) {
case 3,4,5 -> System.out.println("春季");
case 6,7,8 -> System.out.println("夏季");
case 9,10,11 -> System.out.println("秋季");
case 12,1,2 -> System.out.println("冬季");
default->System.out.println("月份输入有误!");
};
3.5.8、if语句与switch语句比较
- if语句的条件是一个布尔类型值,if条件表达式为true则进入分支,可以用于范围的判断,也可以用于等值的判断,使用范围更广。
- switch语句的条件是一个常量值(byte,short,int,char,枚举,String),只能判断某个变量或表达式的结果是否等于某个常量值,使用场景较狭窄。
- 当条件是判断某个变量或表达式是否等于某个固定的常量值时,使用if和switch都可以,习惯上使用switch更多。当条件是区间范围的判断时,只能使用if语句。
- 另外,使用switch可以利用穿透性,同时执行多个分支,而if...else没有穿透性。
案例1:使用if、switch都可以
使用if实现根据指定的月份输出对应季节
import java.util.Scanner;
/*
* 需求:定义一个月份,输出该月份对应的季节。
* 一年有四季
* 3,4,5 春季
* 6,7,8 夏季
* 9,10,11 秋季
* 12,1,2 冬季
*
* 分析:
* A:指定一个月份
* B:判断该月份是几月,根据月份输出对应的季节
* if
* switch
*/
public class Test15IfOrSwitchDemo1 {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.print("请输入月份:");
int month = input.nextInt();
/*
if (month == 1) {
System.out.println("冬季");
} else if (month == 2) {
System.out.println("冬季");
} else if (month == 3) {
System.out.println("春季");
} else if (month == 4) {
System.out.println("春季");
} else if (month == 5) {
System.out.println("春季");
} else if (month == 6) {
System.out.println("夏季");
} else if (month == 7) {
System.out.println("夏季");
} else if (month == 8) {
System.out.println("夏季");
} else if (month == 9) {
System.out.println("秋季");
} else if (month == 10) {
System.out.println("秋季");
} else if (month == 11) {
System.out.println("秋季");
} else if (mouth == 12) {
System.out.println("冬季");
} else {
System.out.println("你输入的月份有误");
}
*/
// 改进版
if ((month == 1) || (month == 2) || (month == 12)) {
System.out.println("冬季");
} else if ((month == 3) || (month == 4) || (month == 5)) {
System.out.println("春季");
} else if ((month == 6) || (month == 7) || (month == 8)) {
System.out.println("夏季");
} else if ((month == 9) || (month == 10) || (month == 11)) {
System.out.println("秋季");
} else {
System.out.println("你输入的月份有误");
}
input.close();
}
}
案例2:使用switch更好
用year、month、day分别存储今天的年、月、日值,然后输出今天是这一年的第几天。
注:判断年份是否是闰年的两个标准,满足其一即可
1)可以被4整除,但不可被100整除
2)可以被400整除
例如:1900,2200等能被4整除,但同时能被100整除,但不能被400整除,不是闰年
public class Test16IfOrSwitchDemo2 {
public static void main(String[] args) {
int year = 2021;
int month = 12;
int day = 18;
//判断这一天是当年的第几天==>从1月1日开始,累加到xx月xx日这一天
//(1)[1,month-1]个月满月天数
//(2)单独考虑2月份是否是29天(依据是看year是否是闰年)
//(3)第month个月的day天
//声明一个变量days,用来存储总天数
int days = 0;
//累加[1,month-1]个月满月天数
switch (month) {
case 12:
//累加的1-11月
days += 30;//这个30是代表11月份的满月天数
//这里没有break,继续往下走
case 11:
//累加的1-10月
days += 31;//这个31是代表10月的满月天数
//这里没有break,继续往下走
case 10:
days += 30;//9月
case 9:
days += 31;//8月
case 8:
days += 31;//7月
case 7:
days += 30;//6月
case 6:
days += 31;//5月
case 5:
days += 30;//4月
case 4:
days += 31;//3月
case 3:
days += 28;//2月
//在这里考虑是否可能是29天
if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) {
days++;//多加1天
}
case 2:
days += 31;//1月
case 1:
days += day;//第month月的day天
}
//输出结果
System.out.println(year + "年" + month + "月" + day + "日是这一年的第" + days + "天");
}
}
案例3:只能使用if
从键盘输入一个整数,判断是正数、负数、还是零。
import java.util.Scanner;
public class Test17IfOrSwitchDemo3 {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.print("请输入整数:");
int num = input.nextInt();
if (num > 0) {
System.out.println(num + "是正整数");
} else if (num < 0) {
System.out.println(num + "是负整数");
} else {
System.out.println(num + "是零");
}
input.close();
}
}
四、循环结构
4.1、场景引入
public static void main(String[] args){
System.out.println("好好学习,天天向上!");
System.out.println("好好学习,天天向上!");
System.out.println("好好学习,天天向上!");
System.out.println("好好学习,天天向上!");
System.out.println("好好学习,天天向上!");
}
假如我现在需要连续输出100次的"好好学习,天天向上!",那么就意味着需要连续写100遍,很麻烦。
但是会发现的规律是:输出的内容是一样的,在不停的循环输出,并且条件是输出100遍。其实,在Java中,针对这样的需求提供了专门的语句:就叫做循环语句。
循环语句可以在满足循环条件的情况下,反复执行某一段代码,这段被重复执行的代码被称为循环体语句。
循环语句的分类:
- while 循环
- for 循环
- do...while 循环
4.2、for 循环
4.2.1、语法格式
for(初始化表达式; 循环条件; 条件控制语句){
执行语句
………
}
在上面的语法结构中,for关键字后面()中包括了三部分内容:初始化表达式、循环条件和条件控制语句,它们之间用“;”分隔,{}中的执行语句为循环体。
注意:
(1)for(;;)中的两个;是不能多也不能少
(2)循环条件必须是boolean类型
执行流程:
① 执行初始化表达式
② 执行循环条件判断语句,看其结果是true还是false
如果是false,循环结束
如果是true,继续执行
③执行循环体语句
④执行条件控制语句
⑤回到②继续
4.2.2、案例1
需求:在控制台输出1-5和5-1的数据。
public static void main(String[] args) {
//需求:输出数据1-5
for(int i=1; i<=5; i++) {
System.out.println(i);
}
System.out.println("--------");
//需求:输出数据5-1
for(int i=5; i>=1; i--) {
System.out.println(i);
}
}
4.2.3、案例2
public static void main(String[] args) {
//求和的最终结果必须保存起来,需要定义一个变量,用于保存求和的结果,初始值为0
int sum = 0;
//从1开始到5结束的数据,使用循环结构完成
for(int i=1; i<=5; i++) {
//将反复进行的事情写入循环结构内部
//此处反复进行的事情是将数据 i 加到用于保存最终求和的变量 sum 中
sum += i;
}
System.out.println(sum);
}
4.2.4、案例3
public static void main(String[] args) {
//求和的最终结果必须保存起来,需要定义一个变量,用于保存求和的结果,初始值为0
int sum = 0;
//对1-100的数据求和与1-5的数据求和几乎完全一样,仅仅是结束条件不同
for(int i=1; i<=100; i++) {
//对1-100的偶数求和,需要对求和操作添加限制条件,判断是否是偶数
if(i%2 == 0) {
sum += i;
}
}
//当循环执行完毕时,将最终数据打印出来
System.out.println("1-100之间的偶数和是:" + sum);
}
4.2.5、案例4
/*
输出所有的水仙花数,所谓水仙花数是指一个3位数,其各个位上数字立方和等于其本身。
例如:153 = 1*1*1 + 3*3*3 + 5*5*5
*/
class ForTest2{
public static void main(String[] args){
for(int i = 100;i <= 999;i++){
int a = i / 100; //获取百位
int b = i % 100 /10; //获取十位
int c = i % 10; //获取个位
if(a*a*a + b*b*b + c*c*c == i){
System.out.println("此数值为满足条件的水仙花数:" + i);
}
}
}
}
4.3、while 循环
4.3.1、语法格式
初始化语句;
while (条件判断语句) {
循环体语句;
条件控制语句;
}
执行流程:
① 执行初始化语句
② 执行条件判断语句,看其结果是true还是false
如果是false,循环结束
如果是true,继续执行
③ 执行循环体语句
④ 执行条件控制语句
⑤ 回到②继续
4.3.2、案例1
public static void main(String[] args) {
//while循环实现打印10次HelloWorld
//定义初始化变量
int i = 1;
//循环条件<=10
while(i<=10){
System.out.println("HelloWorld");
// 改变步长
i++;
}
}
4.3.3、案例2
public static void main(String[] args){
//遍历100以内的所有偶数
int i = 1;
while(i <= 100){
if(i % 2 == 0){
System.out.println(i);
}
i++;
}
}
4.4、do...while循环
4.4.1、语法格式
初始化语句;
do {
循环体语句;
条件控制语句;
}while(条件判断语句);
执行流程:
① 执行初始化语句
② 执行循环体语句
③ 执行条件控制语句
④ 执行条件判断语句,看其结果是true还是false
如果是false,循环结束
如果是true,继续执行
⑤ 回到②继续
4.4.2、案例1
public static void main(String[] args) {
int x=1;
do {
System.out.println("HelloWorld");
x++;
}while(x<=10);
}
4.4.3、案例2
public static void main(String[] args){
do{
System.out.println("无条件执行一次");
}while(false);
}
do...while循环的特点:无条件执行一次循环体,即使我们将循环条件直接写成false,也依然会循环一次。
4.4.4、案例3
public static void main(String[] args){
//遍历100以内的所有偶数,并计算所有偶数的和和偶数的个数
int number = 1;
int sum = 0; //记录总和
int count = 0; //记录个数
do{
if(number % 2 == 0){
System.out.println(number);
sum += number;
count++;
}
number++;
}while(number <= 100);
System.out.println("总和为:" + sum);
System.out.println("个数为:" + count);
}
4.5、三种循环的区别
-
三种循环的区别
- for循环和while循环先判断条件是否成立,然后决定是否执行循环体(先判断后执行)
- do...while循环先执行一次循环体,然后判断条件是否成立,是否继续执行循环体(先执行后判断)
-
for循环和while的区别
-
条件控制语句所控制的自增变量,因为归属for循环的语法结构中,在for循环结束后,就不能再次被访
问到了。
-
条件控制语句所控制的自增变量,对于while循环来说不归属其语法结构中,在while循环结束后,该变
量还可以继续使用。
-
在已知循环次数的时候使用推荐使用for,循环次数未知的时推荐使用while。
-
4.6、死循环
也就是循环中的条件永远为true,死循环的是永不结束的循环。对于死循环来说,是需要满足一个条件之后,退出循环的。
无限循环存在的原因是并不知道循环多少次,而是根据某些条件,来控制循环。
死循环的有下面三种格式: