![](https://i-blog.csdnimg.cn/blog_migrate/ab7f29008ab3dd7175370d2869ab0dca.png)
Java 流程控制
一、用户交互 Scanner
- 我们之前学的基本语法中我们并没有实现程序和人的交互,但是
Java
给我们提供了一个工具类,我们可以获取用户的输入。java.util.Scanner
是Java 5
的新特征,我们可以通过Scanner
类来获取用户的输入。 具体实现步骤:- 导入类:
import java.util.Scanner;
。 Scanner
实例化:创建Scanner
对象,基本语法:Scanner scan = new Scanner(System.in);
。- 获取输入:通过
Scanner
类的next()
与nextLine()
方法获取输入的字符串,在读取前我们一般需要使用hasNext()
与hasNextLine()
方法判断是否有输入的数据。 - 关闭
Scanner
:scan.close();
。- 凡是属于
IO
流的类如果不关闭会一直占用资源,要养成好习惯用完就关掉。 - 调用
close
方法并不仅仅关闭Scanner
类,同时关闭了初始化时作为参数传入的System.in
对象。因此,在close
之后就不可以再使用Scanner
类。
- 凡是属于
- 导入类:
next()
与nextLine()
区别:next()
- 一定要读取到有效字符后才可以结束输入。
- 对输入有效字符之前遇到的空白,
next()
方法会自动将其去掉。 - 只有输入有效字符后才将其后面输入的空白作为分隔符或者结束符。
next()
不能得到带有空格的字符串。
nextLine()
- 以
Enter
为结束符,也就是说nextLine()
方法返回的是回车之前的所有字符。 - 可以获得空白字符串。
- 以
- 如果要输入
int
、double
和boolean
等其他类型的数据,在Scanner
类中也有支持(nextInt()
、nextDouble()
和nextBoolean()
等),但是在输入之前最好先使用hasNextXxx()
方法进行验证,再使用nextXxx()
方法来读取。 - 如果输入的数据类型与要求的类型不匹配时,会报
InputMismatchException
异常导致程序终止。 - 获取
char
类型数据:scan.next().charAt(0); // 获取索引为0位置上的字符
Scanner
实例:输入多个数字,并求其总和与平均数。import java.util.Scanner; public class Demo03 { public static void main(String[] args) { int num = 2; double sum = 0.0; // 创建一个扫描器对象,用于接收键盘数据 Scanner scanner = new Scanner(System.in); System.out.print("请输入第1个数字:"); // 判断用户有没有数值输入 while (scanner.hasNextDouble()){ // 使用nextDouble接收double类型数值 double d = scanner.nextDouble(); System.out.print("请输入第"+num+"个数字:"); // 计算总和 sum += d; // 统计输入的数字总数 num++; } System.out.println("一共输入"+(num-2)+"个数字"); System.out.println("输入数字的总和:"+sum); System.out.println("平均数:"+sum/(num-2)); } }
hasNextXxx()
方法是判断是否还有下一个输入项,如果有则返回true
。而当没有输入项时,该函数会在等待读取输入的情况下阻塞进程,不会返回false
。此情况可以设置一个终止符,例:调用hasNext()
的重载方法hasNext(String patten)
,如果下一个输入项与指定字符串匹配,则返回true
。否则扫描器不执行任何操作。示例如下:while (!sc.hasNext("0")) { System.out.println(sc.next()); }
二、顺序结构
- 顺序结构的程序设计是最简单的,只要按照解决问题的顺序写出相应的语句就行,它的执行顺序是自上而下,依次执行,中间没有任何判断和跳转。
Java
的基本结构就是顺序结构,除非特别指明,否则就按照顺序一句一句执行。- 语句与语句之间,框与框之间是按从上到下的顺序进行的,它是由若干个一次执行的处理步骤组成的,它是任何一个算法都离不开的一种基本算法结构。
三、选择结构
\quad 根据选择条件,选择性的执行某段代码。
3.1 if 单选择结构
-
我们很多时候需要去判断一个东西是否可行,然后我们才去执行,这样一个过程在程序中用
if
语句来表示。
-
语法:
if (boolean_expression) { // 如果布尔表达式为true,则执行的语句 }
3.2 if 双选择结构
- 那现在有个需求,如果用户输入的数值大于等于
60
表示及格,否则表示不及格。这样的需求用一个if
就搞不定了,我们需要有两个判断,需要一个双选择结构,所以就有了if-else
结构。
- 语法:
if (boolean_expression) { // 如果布尔表达式为 true,则执行的语句。 } else { // 如果布尔表达式为 false,则执行的语句。 // else 结构是可选的 }
- 示例:
import java.util.Scanner; public class SelectionIfElse { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); System.out.println("请输入成绩:"); double score = scanner.nextDouble(); if (score >= 60) { System.out.println("及格"); } else { System.out.println("不及格"); } scanner.close(); } }
3.3 if 多选择结构
- 我们发现刚才的代码不符合实际情况,真实的情况还可能存在
A、B、C、D
,存在区间多级判断。例:90~100
就是A
;80~90
就是B
… 等,在生活中我们很多时候的选择也不仅仅只有两个,所以我们需要一个多选择结构来处理这类问题!
- 语法:
if (boolean_expression 1) { // 如果布尔表达式 1 的值为 true,则执行的语句。 } else if (boolean_expression 2) { // 如果布尔表达式 2 的值为 true,则执行的语句。 } else if (boolean_expression 3) { // 如果布尔表达式 3 的值为 true,则执行的语句。 } ...... } else { // 如果以上布尔表达式的值都不为 true,则执行的语句。 // else 结构是可选的 }
- 示例:
import java.util.Scanner; public class SelectionIfElseIf { public static void main(String[] args) { // 考试分数大于等于 60 分就是及格,小于 60 分不及格 Scanner scanner = new Scanner(System.in); System.out.print("请输入成绩(0~100):"); double score = scanner.nextDouble(); // 级别判断 if (score == 100) { System.out.println("恭喜满分"); } else if (score >= 90 && score < 100) { System.out.println("A级"); } else if (score >= 80 && score < 90) { System.out.println("B级"); } else if (score >= 70 && score < 80) { System.out.println("C级"); } else if (score >= 60 && score < 70) { System.out.println("D级"); } else if (score >=0 && score < 60) { System.out.println("不及格"); } else { System.out.println("输入成绩不合法!"); } } }
3.4 嵌套的 if 结构
- 使用嵌套的
if...else
语句是合法的,也就是说你可以在另一个if
或者else if
语句中使用if
或者else if
语句。 - 语法:
if (boolean_expression 1) { // 当布尔表达式 1 为真时执行 if (boolean_expression 2) { // 当布尔表达式 2 为真时执行 } else if (boolean_expression 3) { // 当布尔表达式 2 为假,布尔表达式 3 为真时执行 } else { // 当布尔表达式 2、3 为假时执行 // else 结构是可选的 } } else if (boolean_expression 4) { // 当布尔表达式 1 为假,布尔表达式 4 为真时执行 } else { // 当布尔表达式 1、4 为假时执行 // else 结构是可选的 }
3.5 switch 多选择结构
- 多选择结构还有一个实现方式就是
switch case
语句。 switch case
语句判断一个变量与一系列值中某个值是否相等,每个值称为一个分支。- 语法:
switch(expression){ case value : //语句 break; //可选 case value : //语句 break; //可选 //你可以有任意数量的case语句 default : //可选 //语句 }
switch-case
语句有如下规则:switch
语句中的表达式数据类型可以是:byte
,short
,int
或char
。从Java 5
开始,switch
开始支持枚举enum
类型(后续讲解)。从Java 7
开始,switch
开始支持字符串String
类型,同时case
标签必须为字符串常量或字面量。switch
语句可以拥有多个case
语句。每个case
后面跟一个要比较的值和冒号。case
后面只能声明常量,不能声明范围。case
中的break
语句是可选的。
case
语句中的值的数据类型必须与变量的数据类型相同,而且只能是常量或者字面常量。- 如果
switch-case
结构中的多个case
的执行语句相同,则可以考虑将多个case
进行合并。 - 当变量的值与
case
语句的值相等时,case
语句之后的语句开始执行,直到break
语句出现才会跳出switch
语句。 - 当遇到
break
语句时,switch
语句终止。程序跳转到switch
语句后面的语句执行。case
语句不必须要包含break
语句。如果没有break
语句出现,程序会继续执行下一条case
语句,直到出现break
语句或运行至switch-case
语句末尾结束(如果default
分支存在则会执行default
分支)。 switch
语句可以包含一个default
分支(也可以不包含),该分支一般是switch
语句的最后一个分支(可以在任何位置,但建议在最后一个)。default
分支在变量值与case
语句的值皆不等时执行。default
分支不需要break
语句。- 当
default
分支不在switch
语句末尾时,执行完default
分支语句后会继续执行case
语句,直到出现break
语句。
- 示例
1
:美国队长中的人物import java.util.Scanner; public class SwichCase { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); System.out.print("请输入美国队长中的人物:"); String captainAmerica = scanner.nextLine(); switch (captainAmerica){ case "Steve Rogers": System.out.println("美国队长 "+captainAmerica); break; case "Thor Odinson": System.out.println("雷神托尔 "+captainAmerica); break; case "Robert Bruce Banner": System.out.println("绿巨人浩克 "+captainAmerica); break; case "Natasha Romanoff": System.out.println("黑寡妇 "+captainAmerica); break; default: System.out.println("你输入的是:"+captainAmerica); } } }
- 示例
2
:从键盘上输入year
年的"month
"月和"day
"日,输出是year
年的第几天?import java.util.Scanner; public class SwitchCase{ public static void main(String[] args){ Scanner scan = new Scanner(System.in); System.out.print("请输入年份year:"); int year = scan.nextInt(); System.out.print("请输入"+year+"年的month:"); int month = scan.nextInt(); System.out.print("请输入"+year+"年的day:"); int day = scan.nextInt(); int sumDays = 0; switch(month){ case 12: sumDays += 30; case 11: sumDays += 31; case 10: sumDays += 30; case 9: sumDays += 31; case 8: sumDays += 31; case 7: sumDays += 30; case 6: sumDays += 31; case 5: sumDays += 30; case 4: sumDays += 31; case 3: if((year%4==0&&year%100!=0)||year%400==0){ sumDays += 29; }else{ sumDays += 28; } case 2: sumDays += 31; case 1: sumDays += day; } System.out.println(year"年"+month+"月"+day+"日是"+year+"年的第"+sumDays+"天"); } }
- 凡是可以使用
switch-case
的结构,都可以转换为if-else
。反之,不成立。 - 当我们在开发中使用分支结构时,发现既可以使用
switch-case
(switch
表达式的取值情况不多),又可以使用if-else
时,我们优先使用switch-case
。原因:switch-case
执行效率稍高。
3.6 通过 IDEA 反编译
- 查看编译后
class
文件所在位置(设置
→ \rightarrow →Project Structure...
→ \rightarrow →Project
→ \rightarrow →Project compiler output
)。
- 打开
class
文件所在文件夹(F:\IdeaProjects\JavaSE\out
)
- 将
SwichCase.class
文件复制到IDEA
项目所在文件夹(注:不可直接在IDEA
中操作)
import java.util.Scanner; public class SwichCase { public SwichCase() { } public static void main(String[] args) { Scanner scanner = new Scanner(System.in); System.out.print("请输入美国队长中的人物:"); String captainAmerica = scanner.nextLine(); byte var4 = -1; switch(captainAmerica.hashCode()) { case -644451191: if (captainAmerica.equals("Steve Rogers")) { var4 = 0; } break; case -178896433: if (captainAmerica.equals("Thor Odinson")) { var4 = 1; } break; case 2087830051: if (captainAmerica.equals("Robert Bruce Banner")) { var4 = 2; } break; case 2119186150: if (captainAmerica.equals("Natasha Romanoff")) { var4 = 3; } } switch(var4) { case 0: System.out.println("美国队长 " + captainAmerica); break; case 1: System.out.println("雷神托尔 " + captainAmerica); break; case 2: System.out.println("绿巨人浩克 " + captainAmerica); break; case 3: System.out.println("黑寡妇 " + captainAmerica); break; default: System.out.println("你输入的是:" + captainAmerica); } } }
四、循环结构
\quad
根据循环条件,重复性的执行某段代码。Java
提供了三种循环:while
循环、do...while
循环和for
循环。循环语句由四个部分组成:初始化部分、循环条件部分、循环体部分和迭代部分。
![](https://i-blog.csdnimg.cn/blog_migrate/d60f1f27d80f1197cc045c6fa82e35da.png)
4.1 while 循环
while
循环是最基本的循环,它的结构为:// 初始化部分 while(boolean_expression) { // 循环体 // 迭代部分 }
- 只要循环条件
boolean_expression
布尔表达式为true
,循环就会一直执行下去。 - 我们大多数情况是会让循环停止下来的,我们需要一个让布尔表达式失效的方式来结束循环。
- 少部分情况需要循环一直执行,例:服务器的请求响应监听等。
- 循环条件一直为
true
(while(true)
)或没有迭代语句会造成无限循环(死循环),正常的业务编程中应避免死循环。 - 结束循环的方式:1.循环条件部分返回
false
。2.在循环体中,执行break
。 while
循环可以嵌套,最多不要超过三层嵌套。设外层循环为m
次,内层为n
次,则内层循环体实际上执行m*n
次。嵌套循环的外层循环控制行数,内层循环控制列数。
4.2 do…while 循环
- 对于
while
语句而言,如果不满足条件,则不能进入循环。但有时候我们需要即使不满足条件,也至少执行一次。这时就需要用到do...while
循环,它的结构为:// 初始化部分 do { // 循环体 // 迭代部分 } while(boolean_expression);
do...while
循环和while
循环相似,不同的是,do…while
循环的布尔表达式在循环体的后面,所以循环体在判断布尔表达式之前已经被执行了,因此do…while
循环至少会执行一次。 如果布尔表达式的值为true
,则循环体一直执行,直到布尔表达式的值为false
。do...while
循环可以嵌套,最多不要超过三层嵌套。设外层循环为m
次,内层为n
次,则内层循环体实际上执行m*n
次。嵌套循环的外层循环控制行数,内层循环控制列数。while
循环和do...while
循环的区别:while
循环先判断布尔表达式然后执行循环体。do...while
循环则是先执行循环体然后判断布尔表达式。do...while
循环总是保证循环体会被至少执行一次。
4.3 for 循环
- 虽然所有循环结构都可以用
while
或do...while
表示,但Java
提供了另一种语句 ——for
循环,使一些循环结构变得更加简单。 for
循环执行的次数是在执行前就确定的。语法格式如下:for(初始化部分; 循环条件; 迭代部分) { //循环体部分 }
- 关于
for
循环有以下几点说明:- 最先执行初始化步骤。可以声明一种数据类型,但是可初始化一个或多个循环控制变量,也可以是空语句。
- 然后,检测布尔表达式的值,可以是空语句。如果为
true
,循环体被执行。如果为false
,循环终止,开始执行循环体后面的语句。 - 执行一次循环后,更新循环控制变量,可以不更新,即空语句。
- 再次检测布尔表达式。循环执行上面的过程。
- 结束循环的方式:1.循环条件部分返回
false
。2.在循环体中,执行break
。 - 循环条件一直为
true
(for(初始化;true;迭代)
)或没有迭代语句(for(;;)
)会造成无限循环(死循环),正常的业务编程中应避免死循环。 for
循环可以嵌套,最多不要超过三层嵌套。设外层循环为m
次,内层为n
次,则内层循环体实际上执行m*n
次。嵌套循环的外层循环控制行数,内层循环控制列数。
for
循环和while
循环是可以相互转换的。唯一区别:for
循环和while
循环的初始化条件部分的作用域不同。- 示例
1
:打印九九乘法表。public class ForDemo01 { public static void main(String[] args) { for (int i = 1; i < 10; i++) { for (int j = 1; j < 10; j++) { if (j <= i) { System.out.printf("%d x %d = ", i, j); System.out.print(i*j+",\t"); } else { break; } } System.out.println(); } } }
- 示例
2
:编写程序从1
循环到150
,并在每行打印一个值,另外在每个3
的倍数行上打印出“foo
”,在每个5
的倍数行上打印“biz
”,在每个7
的倍数行上打印输出“baz
”。public class ForDemo02 { public static void main(String[] args){ for(int i = 1;i <= 150;i++) { String str = ""; if(i % 3 == 0) { str += "foo "; } if(i % 5 == 0) { str += "biz "; } if(i % 7 == 0) { str += "baz "; } System.out.println(i+"\t"+str); } } }
- 示例
3
:输出所有的水仙花数,所谓水仙花数是指一个3
位数,其每个位上的数字立方和等于其本身。// 输出所有的水仙花数 public class ForDemo03{ public static void main(String[] args){ for (int i = 100;i < 1000;i++){ int ones = i % 10;// 个位 int onesCube = ones * ones * ones;// 个位立方 int tens = i / 10 % 10;// 十位 int tensCube = tens * tens * tens;// 十位立方 int hundreds = i / 100;// 百位 int hundredsCube = hundreds * hundreds * hundreds;// 百位立方 if (onesCube + tensCube + hundredsCube == i){ System.out.print(i+"\t"); } } } }
- 示例
4
:输出100
以内的所有质数。(质数是指在大于1
的自然数中,除了1
和它本身以外不再有其他因数的自然数)// 输出100以内的质数 public class PrimeNumber{ public static void main(String[] args){ boolean isFlag = true; // 标识i是否被j除尽,一旦除尽,修改其值 int num = 100; // 获取当前时间距离1970-01-01 00:00:00 的毫秒数 long start = System.currentTimeMillis(); for (int i = 2; i <= num; i++){ // 遍历从1~100的数字 for (int j = 2; j <= Math.sqrt(i); j++){ if (i % j == 0){ // 如果数字能被1和自身以外的数字整除,跳出循环 isFlag = false; break; } } if (isFlag == true){ System.out.print(i+","); // i为质数 } // 重置isFlag isFlag = true; } // 获取当前时间距离1970-01-01 00:00:00 的毫秒数 long end = System.currentTimeMillis(); System.out.print("所花费的时间为:"+(end - start)); } }
4.4 增强型 for 循环
- 增强型
for
循环在之后的数组中会重点使用。 Java 5
引入了一种主要用于数组或集合的增强型for
循环。Java
增强for
循环语法格式如下:for (声明语句 : 表达式) { //代码句子 }
- 声明语句:声明新的局部变量,该变量的类型必须和数组元素的类型匹配。其作用域限定在循环语句块,其值与此时数组元素的值相等。
- 表达式:表达式是要访问的数组名,或者是返回值为数组的方法。
- 示例:遍历数组元素。
public class ForEach { public static void main(String[] args) { int num = 1; int[] numArray = {10,20,30,40,50,60,70,80,90,100}; for (int i : numArray) { System.out.println("第 "+num+" 个元素:"+i); num++; } } }
五、break & continue
5.1 break 关键字
break
主要用在循环控制结构或switch-case
语句中,用来跳出整个语句块。break
用于强行跳出最里层的循环,并且不执行本层循环中剩余的语句,然后继续执行循环外层的语句。break
关键字后面不能声明执行语句,因为永远不会被执行。- 示例:求两个正整数的最大公约数和最小公倍数。
//求两个正整数的最大公约数和最小公倍数 import java.util.Scanner; public class ForDemo2{ public static void main(String[] args){ Scanner scan = new Scanner(System.in); System.out.print("请输入第一个正整数:"); int num1 = scan.nextInt(); System.out.print("请输入第二个正整数:"); int num2 = scan.nextInt(); // 获取最大公约数 int gcd = 1; int minNum = num1 <= num2 ? num1 : num2;// 获取两个数中较小的数 for (int i = minNum;i >= 1;i--){ if (num1 % i == 0 && num2 % i == 0){ gcd = i; break; } } System.out.println(num1+"和"+num2+"的最大公约数是:"+gcd); // 获取最小公倍数 int lcm = num1 * num2; int maxNum = num1 >= num2 ? num1 : num2;// 获取两个数中较大的数 for (int i = maxNum;i <= lcm;i++){ if (i % num1 == 0 && i % num2 == 0){ lcm = i; break; } } System.out.println(num1+"和"+num2+"的最小公倍数是:"+lcm); } }
5.2 continue 关键字
continue
适用于任何循环控制结构中。作用是让程序终止某次循环,即跳过循环体中尚未执行的语句,然后直接跳转到下一次循环的迭代。continue
关键字后面不能声明执行语句,因为永远不会被执行。- 在
for
循环中,continue
语句使程序立即跳转到更新语句。 - 在
while
或者do...while
循环中,程序立即跳转到布尔表达式的判断语句。
5.3 标签
Java
中的label
标签必须放在循环之前,一定要紧跟循环,标签是为循环设计的,是为了在多重循环中方便的使用break
和coutinue
。- 带标签的循环实际上就是给这个循环起了个名字,当使用 “
continue
/break
+ 标签” 语句时实际上就是在标签所在的循环执行continue
(或break
)语句。 label
标签必须放在循环之前,一定要紧跟循环。- 使用
break lable
进行跳转时,只能从内层跳转到外层语句块,而不能从外层调到内层或平行的代码块。 - 带标签的
break
是跳出循环到label
标签处而继续执行label
标签对应循环体后边的语句;带标签的continue
是直接进行label
标签对应循环体的下一次循环。 - 注:带标签的
break
和coutinue
实现的功能类似于其他设计语言中goto
关键字,但是goto
是Java
中的一个保留字,并未在语言中得到正式使用。 - 示例:
break lable
public class LabelDemo01 { public static void main(String[] args) { out:for(int i = 0; i < 10; i++){ System.out.println(); for(int j = 0; j < 10; j++){ if(j == 5){ break out; } System.out.print("("+i+","+j+") "); } } System.out.println("End"); } } // 输出结果:(0,0) (0,1) (0,2) (0,3) (0,4) End
continue lable
public class LabelDemo02 { public static void main(String[] args) { out:for(int i = 0; i < 10; i++){ System.out.println(); for(int j = 0; j < 10; j++){ if(j == 5){ continue out; } System.out.print("("+i+","+j+") "); } } System.out.println("End"); } } // 输出结果: // (0,0) (0,1) (0,2) (0,3) (0,4) // (1,0) (1,1) (1,2) (1,3) (1,4) // (2,0) (2,1) (2,2) (2,3) (2,4) // (3,0) (3,1) (3,2) (3,3) (3,4) // (4,0) (4,1) (4,2) (4,3) (4,4) // (5,0) (5,1) (5,2) (5,3) (5,4) // (6,0) (6,1) (6,2) (6,3) (6,4) // (7,0) (7,1) (7,2) (7,3) (7,4) // (8,0) (8,1) (8,2) (8,3) (8,4) // (9,0) (9,1) (9,2) (9,3) (9,4) End
六、练习
- 以数字打印出三角形
public class CycleTest { public static void main(String[] args) { int num = 1; int line = 10; for (int i = 0; i < line; i++) { int a = line - 1 -i; while (a > 0) { System.out.print("\t"); a--; } for (int j = 1;;j++) { if (j <= (2*i+1)){ System.out.print(num + "\t"); num++; } else { System.out.println(); break; } } } } }
- 输出结果: