流程控制
- 简单来讲所谓流程就是完成一件事情的多个步骤组合起来就叫做一个流程。
- 在一个程序执行的过程中,各条语句的执行顺序对程序的结果是有直接影响的。
- 我们必须清楚每条语句的执行流程。而且,很多时候要通过控制语句的执行顺序来实现我们想要的功能。
- 流程控制语句分为:顺序结构 丶分支结构(if, switch) 丶循环结构(for, while, do…while)。
下面我们来详细学习一下吧
顺序结构
任何编程语言中最常见的程序结构就是顺序结构。顺序结构就是程序从上到下逐行地执行,中间没有任何判断和跳转。如果main方法的多行代码之间没有任何流程控制,则程序总是从上向下依次执行,排在前面的代码先执行,排在后面的代码后执行。
顺序结构执行流程图:
代码示例
public class Demo01Sequence {
public static void main(String[] args) {
//1.顺序结构: 按照代码的书写顺序,从上而下依次执行
System.out.println("开始.....");
System.out.println("A");
System.out.println("B");
System.out.println("C");
System.out.println("结束....");
}
}
分支结构
分支结构用于实现根据条件来选择性地执行某段代码。在Java语句中包括 if和switch 2种语句。
分支结构中的if语句
if适合做区间匹配。
if语句第一种格式: 单if
执行流程:
- 首先计算关系表达式的值
- 如果关系表达式的值为true就执行语句体
- 如果关系表达式的值为false就不执行语句体
- 继续执行后面的语句内容
执行流程图
代码示例
package sgg.demo01;
/*
案例:从键盘输入年份,请输出该年的2月份的总天数。闰年2月份29天,平年28天。
闰年:
(1)能被4整除,不能被100整除 或者 能被400整除
*/
public class Demo01 {
public static void main(String[] args) {
java.util.Scanner input = new java.util.Scanner(System.in);
System.out.print("请输入年份:");
int year = input.nextInt();
int days = 28;
if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) {
days++;
}
System.out.println(year + "年的2月份共" + days + "天");
}
}
注意事项:
- if语句的第一种格式,适用于有一种情况的场景
- if后面小括号中表达式的最终的结果一定是布尔类型,要么是true,要么是false
- if后面大括号中的语句体: 一条或者多条语句(每条语句末尾处使用分号结尾)
- if后面大括号中的语句体的语句体只有一条语句,此时大括号可以省略,不建议省略。省略大括号后,只对第一行语句有效
import java.util.Scanner;
public class Demo02Scanner {
public static void main(String[] args) {
//input是变量名
Scanner input = new Scanner(System.in);
System.out.print("年龄:");
int age = input.nextInt();
if (age >= 18)
//省略大括号,相当于只有一行语句在大括号里
System.out.println("年龄是:" + age + "成年人..");
System.out.println("好好工作..");
System.out.println("后续代码");
}
}
if语句第二种格式: if...else
执行流程:
- 首先计算关系表达式的值
- 如果关系表达式的值为true就执行语句体1
- 如果关系表达式的值为false就执行语句体2
- 继续执行后面的语句内容
执行流程图
代码示例
package sgg.demo01;
public class Demo02 {
public static void main(String[] args) {
int a = 10;
int b = 20;
//定义变量,保存a和b的较大值
int max;
if(a > b) {
max = a;
} else {
max = b;
}
System.out.println(max);
//可以上述功能改写为三元运算符形式
max = a > b ? a : b;
System.out.println(max);
}
}
注意事项:
- 在某些简单的应用中,if语句是可以和三元运算符互换使用的。
- if语句的第二种格式,适用于有二选一的场景
- if后面小括号中表达式最终的结果一定是布尔类型,要么是true,要么是false
- if后面大括号中的语句体的语句体只有一条语句,此时大括号可以省略,不建议省略。省略大括号后,只对第一行语句有效。下面的代码编译报错
public class Demo02If {
public static void main(String[] args) {
//input是变量名
Scanner input = new Scanner(System.in);
System.out.print("年龄:");
int age = input.nextInt();
if (age >= 18)
System.out.println("成年人");
System.out.println("出去工作..");
else{
System.out.println("未成年人,好好读书");
}
System.out.println("后续代码");
}
}
if语句第三种格式: if...else if ...else
执行流程
- 首先判断关系表达式1看其结果是true还是false
- 如果是true就执行语句体1,然后结束当前多分支
- 如果是false就继续判断关系表达式2看其结果是true还是false
- 如果是true就执行语句体2,然后结束当前多分支
- 如果是false就继续判断关系表达式…看其结果是true还是false
- …
- 如果没有任何关系表达式为true,就执行语句体n+1,然后结束当前多分支。
执行流程图
代码示例
import java.util.Scanner;
/*
需求:
小明快要期末考试了,小明爸爸对他说,会根据他不同的考试成绩,送他不同的礼物,
假如你可以控制小明的得分,请用程序实现小明到底该获得什么样的礼物,并在控制台输出。
奖励规则:
95~100 山地自行车一辆 包含95和100的 数学中表示方式: [95,100] 不包含95和100: (95,100)
90~94 游乐场玩一次 包含90和94的
80~89 变形金刚玩具一个 包含80和89的
80以下 胖揍一顿 不包含80分的
*/
public class Demo03{
public static void main(String[] args) {
//1.创建键盘录入Scanner类的对象
Scanner sc = new Scanner(System.in);
//2.获取一个0-100之间的整数数字(代表小明的考试成绩),保存到int变量score中
System.out.println("请输入一个0-100之间的整数数字(代表小明的考试成绩): ");
int score = sc.nextInt();
//3.因为score中的数字有多种(大于3)情况,所以使用if语句的第三种格式进行判断,并输出不同的结果内容
if (score >= 95 && score <= 100) {
System.out.println("奖励山地自行车一辆");
} else if (score >= 90 && score <= 94) {
System.out.println("奖励游乐场玩一次");
} else if (score >= 80 && score <= 89) {
System.out.println("奖励变形金刚玩具一个");
} else if (score >= 0 && score < 80) {
System.out.println("奖励胖揍一顿");
} else { //隐藏条件: score<0 || score>100
System.out.println("您输入的成绩错误,是火星来的吧,哥屋恩...");
}
System.out.println("main....end....");//模拟格式中的其它语句
}
}
注意事项
- if语句的第三种格式,适用于有多种情况(大于等于3)的场景
- 这么多条件表达式是顺序往下判断的,如果上面有条件成立了,下面的就不判断了;如果上面的条件不成立,才会去判断下面条件。
- if后面小括号中表达式不管写的多么简单或者多么复杂,最终的结果一定是布尔类型,要么是true,要么是false
- 语句体1到语句体n+1,只有一个会被执行。适用于多选一的场景
- 有if就可以在后面写条件,没有if,不能写条件,不能直接在else后面写条件
- 如果上面所有if后的条件都不成立,直接执行最后一个else中的代码
- 当多个条件的范围是“互斥”(没有重叠部分),顺序可以随意;
- 当多个条件的范围是“包含”(有重叠部分),顺序不能随意,小的在上,大的在下
if..else嵌套
- 在if的语句块中,或者是在else语句块中,又包含了另外一个条件判断(可以是单分支、双分支、多分支)。
执行的特点:
- 如果是嵌套在if语句块中的,只有当外部的if条件满足,才会去判断内部的条件
- 如果是嵌套在else语句块中的,只有当外部的if条件不满足,进入else后,才会去判断内部的条件
代码示例
package sgg.demo01;
import java.util.Scanner;
//从键盘输入一个年份,和月份,输出该年份该月的总天数
public class Demo04 {
public static void main(String[] args) {
//从键盘输入一个年份,和月份
Scanner input = new Scanner(System.in);
System.out.print("年份:");
int year = input.nextInt();
System.out.print("月份:");
int month = input.nextInt();
if (year > 0) {
if (month >= 1 && month <= 12) {
//全部合法的情况
int days;
if (month == 2) {
if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) {
days = 29;
} else {
days = 28;
}
} else if (month == 4 || month == 6 || month == 9 || month == 11) {
days = 30;
} else {
days = 31;
}
System.out.println(year + "年" + month + "月有" + days + "天");
} else {
//年份合法,月份不合法的情况
System.out.println("月份输入不合法");
}
} else {
//年份不合法的情况
System.out.println("年份输入不合法");
}
}
}
分支结构中的switch语句
适合做值匹配的分支选择,结构清晰,格式良好。
语法格式:
执行流程:
- 首先,计算出表达式的值
- 其次,和case依次比较,一旦有对应的值,就会执行相应的语句,在执行的过程中,遇到break就会结束。
- 最后,如果所有的case都和表达式的值不匹配,就会执行default语句体部分,不管default在哪里 ,然后程序遇到了switch的最后一个大括号就结束掉。
执行流程图
代码演示
package demo03;
public class SwitchDemo01 {
public static void main(String[] args) {
//定义指定的星期
int weekday = 5;
//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;
}
}
}
注意事项:
- break的作用是用来结束switch语句的,一旦执行break,直接跳出到switch外面的其它语句继续执行
- switch(表达式)的值的类型,只能是:byte,short,int,char,JDK1.5之后枚举、JDK1.7之后String
- case 后面只能写常量,而且常量值不能重复
- case 后的数值类型必须与表达式的类型一致
- 如果所有的case后面的常量值和switch中表达式的值都不相同,就执行default中的内容。default如果放在最后的话,后面的break可以省略
- 如果所有的case和default后面都有break,那么default和case的顺序可以任意排列,不影响最终的结果
case的穿透性
- 在switch语句中,如果case的后面不写break,将出现穿透现象
- 也就是一旦匹配成功,不会在判断下一个case的值,直接向后运行,直到遇到break或者整个switch语句结束,switch语句执行终止。
执行步骤:
- 先找到case入口:先找到常量值和switch表达式值相同的case
- 执行找到的case入口中的代码,如果没有break,直接执行(不再判断下一个case中的常量值是否和switch表达式的值是否相同)下一个case中的代码,
- 直到遇到break或者将整体switch语句执行完毕,才会结束。
代码示例
import java.util.Scanner;
/*
需求:
一年有12个月,分属于春夏秋冬4个季节,
键盘录入一个月份,请用程序实现判断该月份属于哪个季节,并输出。
演示效果
输入: 1、2、12 输出:冬季
输入: 3、4、5 输出:春季
输入: 6、7、8 输出:夏季
输入: 9、10、11 输出:秋季
输入: 其它数字 输出:数字有误
*/
public class SwitchDemo02 {
public static void main(String[] args) {
//1.创建键盘录入Scanner类的对象
Scanner sc = new Scanner(System.in);
//2.获取键盘录入的一个1-12的整数数字(代表月份),保存到int变量month中
System.out.println("请输入一个1-12的整数数字(代表月份): ");
int month = sc.nextInt();
//3.因为month中的数字有12+1中情况,使用switch语句对month中的值,进行判断,并输出不同的结果
switch (month) {//9
case 1:
case 2:
case 12:
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;
default:
System.out.println("您输入的月份不存在,哪个星球来的,哥屋恩...");
break;
}
System.out.println("main....end....");//模拟格式中的其它语句
}
}
循环概述
循环语句可以在满足循环条件的情况下,反复执行某一段代码,这段被重复执行的代码被称为循环体语句,当反复执行这个循环体时,需要在合适的时候把循环判断条件修改为false,从而结束循环,否则循环将一直执行下去,形成死循环。循环的意义就是用来解决重复的事情..
循环组成
- 初始化表达式:用于表示循环开启时的起始状态,简单说就是循环开始的时候什么样。初始化部分可以声明多个变量,但必须是同一个类型,用逗号分隔。且只执行一次。
- 循环条件:用于表示循环反复执行的条件,简单说就是判断循环是否能一直执行下去。循环结构中判断条件部分必须是布尔类型,当判断条件部分的表达式计算结果为false时,循环结束。
- 循环体:用于表示循环反复执行的内容,简单说就是循环反复执行的事情,循环的意义。
- 步进表达式:用于表示循环执行中每次变化的内容,简单说就是控制循环是否能执行下去。可以有多个变量更新,用逗号分隔
for循环
格式
执行流程
-
第一步:执行初始化语句①,完成循环变量的初始化;
-
第二步:执行循环条件语句②,看循环条件语句的值是true,还是false;
-
如果是true,执行第三步;
-
如果是false,循环语句中止,循环不再执行。
-
-
第三步:执行循环体语句③
-
第四步:执行迭代语句④,针对循环变量重新赋值
-
第五步:根据循环变量的新值,重新从第二步开始再执行一遍
图解分析:
注意事项:
- for(;;)中的两个;是不能多也不能少
- 循环条件必须是boolean类型
- 如果循环条件语句②省略的话,就默认为循环条件成立
代码示例
/*
需求:
在控制台输出所有的“水仙花数”及总个数
解释:什么是水仙花数?
水仙花数,指的是一个三位数,个位、十位、百位的数字立方和等于原数
例如 153 3*3*3 + 5*5*5 + 1*1*1 = 27 + 125 + 1 = 153
*/
public class Demo03For {
public static void main(String[] args) {
//1.定义int变量count,初始值0,作用是统计水仙花数字的个数
int count = 0;
//2.使用for循环遍历获取所有的三位数字,每个数字保存到int变量num中
for (int num = 100; num <= 999; num++) {
//2.1计算num中数字的个位,十位,百位 分别保存到3个int变量ge(个位),shi(十位),bai(百位)中
int ge = num % 10;//个位
int shi = num / 10 % 10;//十位
int bai = num / 100 % 10;//百位
//2.2计算个位,十位,百位数字的立方和,保存到int变量sum中
//2.3判断如果三位数字num 等于 每位数字的立方和sum
if ((ge * ge * ge + shi * shi * shi + bai * bai * bai) == num) {
//输出该数字num
System.out.println(num);
//同时计数器count的值增加1
count++;
}
}
//3.for循环结束后,打印count的值
System.out.println("水仙花数字总共有: " + count + " 个");
}
}
while循环
格式:
执行流程:
-
第一步:执行初始化语句①,完成循环变量的初始化;
-
第二步:执行循环条件语句②,看循环条件语句的值是true,还是false;
-
如果是true,执行第三步;
-
如果是false,循环语句中止,循环不再执行。
-
-
第三步:执行循环体语句③
-
第四步:执行迭代语句④,针对循环变量重新赋值
-
第五步:根据循环变量的新值,重新从第二步开始再执行一遍
图解分析
注意事项:
- while(循环条件)中循环条件必须是boolean类型
代码示例
package demo04;
/*
需求:世界最高山峰是珠穆朗玛峰(8844.43米=8844430毫米),假如我有一张足够大的纸,它的厚度
是0.1毫米。请问,我折叠多少次,可以折成珠穆朗玛峰的高度?
*/
public class Demo05While {
public static void main(String[] args) {
//定义一个计数器,初始值为0
int count = 0;
//定义纸张厚度
double paper = 0.1;
//定义珠穆朗玛峰的高度
int zf = 8844430;
//因为要反复折叠,所以要使用循环,但是不知道折叠多少次,这种情况下更适合使用while循环
// 折叠的过程中当纸张厚度大于珠峰就停止了,因此继续执行的要求是纸张厚度小于珠峰高度
while (paper <= zf) {
//循环的执行过程中每次纸张折叠,纸张的厚度要加倍
paper *= 2;
//在循环中执行累加,对应折叠了多少次
count++;
}
//打印计数器的值
System.out.println("需要折叠:" + count + "次");//需要折叠:27次
}
}
do...while循环
格式:
注意事项:
- while(循环条件)中循环条件必须是boolean类型
- do{}while();最后有一个分号
- do...while结构的循环体语句是至少会执行一次,这个和for和while是不一样的
执行流程:
-
第一步:执行初始化语句①,完成循环变量的初始化;
-
第二步:执行循环体语句②;
-
第三步:执行迭代语句③,针对循环变量重新赋值;
-
第四步:执行循环条件语句④,看循环条件语句的值是true,还是false;
-
如果是true,根据循环变量的新值,重新从第二步开始再执行一遍;
-
如果是false,循环语句中止,循环不再执行。
-
代码示例
/*
输入密码和确认密码,如果两次密码一致则显示注册成功,两次密码不一致则提示重新输入
*/
Scanner input = new Scanner(System.in);
String pwdOne = "";
String pwdTwo = "";
do{
System.out.println("请输入密码");
pwdOne = input.next();
System.out.println("请输入确认密码");
pwdTwo = input.next();
if(!pwdOne.equals(pwdTwo)){
System.out.println("两次密码不一致,请重新输入");
}
}while(!pwdOne.equals(pwdTwo));
System.out.println("注册成功");
从循环次数角度分析
- do...while循环至少执行一次循环体语句
- for和while循环先循环条件语句是否成立,然后决定是否执行循环体,至少执行零次循环体语句
从循环变量的生命周期角度分析
- for循环的循环变量在for()中声明的,在循环语句结束后,不可以被访问;
- while和do...while循环的循环变量因为在外面声明的,所以while和do...while结束后可以被继续使用的;
如何选择
- 功能上是完全一样的,for能解决的while也能解决,反之亦然。
- 遍历有明显的循环次数(范围)的需求,选择for循环
- 遍历没有明显的循环次数(范围)的需求,循环while循环
- 如果循环体语句块至少执行一次,可以考虑使用do...while循环
本质上:三种循环之间是可以互相转换的,都能实现循环的功能
三种循环结构都具有四要素:
- 循环变量的初始化表达式
- 循环条件
- 循环变量的修改的迭代表达式
- 循环体语句块
死循环
也就是循环中的条件永远为true,死循环的是永不结束的循环。
- 例如:while(true){}。 在后期的开发中,会出现使用死循环的场景
- 例如:我们需要读取用户输入的输入,但是用户输入多少数据我们 并不清楚,也只能使用死循环,当用户不想输入数据了,就可以结束循环了,如何去结束一个死循环呢,就需要使用到跳出语句了
下图展示了三种死循环的格式:
break控制语句
使用场景
- 使用在switch语句中,用来结束switch语句,执行switch语句后面的其它语句
- 使用在循环中,用来结束循环(1.本次循环的循环体中break后面的代码不再执行 2.剩余次数的循环也不再执行),执行循环后面的其它语句
- break不能使用在出switch和循环语句以外的其它位置
- 即使break放在嵌套循环中,也只能结束本层循环
- break语句后面,不能紧挨着写任何其他语句,因为任何其他语句都没法执行到
代码示例
public class Demo01Break {
public static void main(String[] args) {
System.out.println("顾客获取到了购买的四个包子..........");
for (int num = 1; num <= 4; num++) {
/*
当num的值为2时,num == 2 --> true,if后面()中是true,执行if后面{}中的内容,
首先: 执行输出语句
其次: 执行break,一旦执行break,本次循环的循环体中break后面的代码不再执行,
剩余次数的循环也不再执行,直接从循环中跳出到循环后面的其它代码继续执行
*/
if (num == 2) {
System.out.println("发现2号包子上有个大家伙(小强),2号(及剩余所有)包子不能吃了,找老板投诉");
break;
}
System.out.println("顾客吃第" + num + "个包子......");
}
System.out.println("顾客投诉: 这是神马包子,岂有此理.老板: 非常抱歉,赔偿100000元~~~~~");
}
}
图解分析:
案例:
//从键盘输入不断输入整数,输入0表示结束,统计一共有几个正数、负数。
public class Demo02Break {
public static void main(String[] args) {
java.util.Scanner input = new java.util.Scanner(System.in);
int positive = 0;
int negative = 0;
while (true) {
System.out.print("请输入整数(0)结束:");
int num = input.nextInt();
if (num == 0) {
break;
} else if (num > 0) {
positive++;
} else {
negative++;
}
}
System.out.println("正数:" + positive + ",负数:" + negative);
}
}
循环标号:
- 当一个switch语句出现在循环中,switch里面使用break只能对switch有效,对循环无效 。如果需要告诉break跳出指定的循环,可以给其起一个标号,例如:
import java.util.Scanner;
public class Test {
/* 需求:程序运行后,用户可多次查询星期对应的减肥计划,直到输入0,程序结束
步骤:
1. 不明确用户操作几次, 使用死循环包裹业务逻辑
2. 匹配到0的时候,使用break结束循环死循环
*/
public static void main(String[] args) {
lo:
while (true) {
System.out.println("请输入您要查看的星期数:");
System.out.println("(如无需继续查看,请输入0退出程序)");
// 1. 键盘录入星期数据,使用变量接收
Scanner sc = new Scanner(System.in);
int week = sc.nextInt();
// 2. 多情况判断,采用switch语句实现
switch (week) {
// 3. 在不同的case中,输出对应的减肥计划
case 0:
System.out.println("感谢您的使用");
break lo;
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;
}
}
}
}
continue控制语句
使用场景:
- 只能使用在循环中,作用是提前结束本次循环,继续进行下一次循环
- 不能使用在除循环结构中的其它位置
- continue语句后面,不能紧挨着写任何其他语句,因为任何其他语句都没法执行到
代码示例
package demo05;
public class Demo03Continue {
public static void main(String[] args) {
System.out.println("顾客获取到了购买的四个包子..........");
for (int num = 1; num <= 4; num++) {
/*
当num的值为2时,num == 2 --> true,if后面()中是true,执行if后面{}中的内容,
首先: 执行输出语句
其次: 执行continue,一旦执行continue,本次循环的循环体中continue后面的代码不再执行,
继续执行下一次循环的步进表达式
总结: continue的作用提前结束本次循环,继续进行下一次循环
*/
if (num == 2) {
System.out.println("把第2个包子弄脏了,不能吃第2个包子了,继续吃其它包子...");
continue;
}
System.out.println("顾客吃第" + num + "个包子......");
}
System.out.println("找老板结账,交钱400块,老板说: 欢迎下次光临....");
}
}
图解分析:
案例:
public class Demo04Continue {
public static void main(String[] args) {
//打印1-100之间的整数,跳过7的倍数和7结尾的数
for (int i = 1; i <= 100; i++) {
if (i % 7 == 0 || i % 10 == 7) {
continue;
}
System.out.println(i);
}
}
}
如果需要告诉continue提前结束指定的循环,继续进行下一次循环,可以给其起一个标号,使用方式和break是一样的。这里代码就不演示了。。
循环嵌套
- 所谓嵌套循环,是指一个循环的循环体是另一个循环。比如for循环里面还有一个for循环,就是嵌套循环。总共的循环次数=外循环次数*内循环次数。当然可以是三种循环任意互相嵌套。
for循环相互嵌套格式
嵌套循环执行流程:
- 执行顺序:①②③④⑤⑥>④⑤⑥>⑦②③④⑤⑥>④⑤⑥
- 外层循环执行1次,内层循环执行完整的(从初始化表达式开始)一遍
图解分析:
代码示例
public class Demo05ForFor {
public static void main(String[] args) {
//打印2021年至2023年月份
// 年份是外循环,3年;月份是内循环,12月
for (int i = 2021; i <= 2023; i++) {
for (int j = 1; j <= 12; j++) {
//不换行打印星号
System.out.print(i + "年" + j + "月 ");
}
//内循环打印12个月后,需要一次换行
System.out.println();
}
}
}