第三章 流程控制语句结构
写程序的最终目的是为了解决日常生活和工作中的问题。日常生活和工作中做的事情和解决方法,需要有一定的步骤和流程。Java使用顺序结构、分支结构、循环结构,将多个语句组合在一起,以便实现和控制任务的执行流程。
3.1 顺序结构
顺序结构是所有流程控制语句结构中最基础的结构,顺序结构的程序从整体来看都是顺序执行的。
3.1.1 顺序结构的特点
Java中的顺序结构指语句按照从上到下的编写顺序依次执行。
3.1.2 输出语句
System.out.println("内容") //输出之后换行
System.out.print("内容"); //输出内容之后不换行
无论是哪一种输出语句,括号中都只能有一个值,要么是一个常量值,要么是一个变量值,要么是一个表达式的计算结果。如果有多个值,那么应考虑使用运算符"+"将它们连接起来。
3.1.3输入语句
在程序运行期间间接接收从控制台输入的数据。使用util包中的Scanner类,示例如下:
import java.util.Scanner; // 导包
public class TestInput{
public static void main(String[] args){
Scanner input = new Scanner(System.in); // 使用Scanner类声明一个变量input
System.out.println("请输入一个整数:");
int num = input.nextInt(); // 接受输入一个int值,并且把值存放在变量num变量。
System.out.println("num =" + num);
}
}
如果输入的是小数会报错,因为输入语句只接受int值,因为Java是强语言类型。如果要接收其他类型的数据,通常使用一下几种数据类型的接收方式:
- Scanner类型的变量.nextByte():用于接收一个byte值;
- Scanner类型的变量.nextShort():用于接收一个short值;
- Scanner类型的变量.nextInt():用于接收一个int值;
- Scanner类型的变量.nextLong():用于接收一个long值;
- Scanner类型的变量.nextFloat():用于接收一个float值;
- Scanner类型的变量.nextDouble():用于接收一个double值;
- Scanner类型的变量.nextBoolean():用于接收一个boolean值;
- Scanner类型的变量.next():用于接收一个String字符串;
- Scanner类型的变量.next().charAt(0):用于接收一个char值。
示例:
import java.util.Scanner;
public class InputInfoDemo{
public static void main(String[] args){
Scanner input = new Scanner(System.in);
System.out.print("请输入姓名:");
String name = input.next();
System.out.print("请输入年龄:");
int age = input.nextInt();
System.out.print("请输入体重:");
double weight = input.nextDouble();
System.out.print("请输入婚否:");
boolean marry = input.nextBoolean();
System.out.print("请输入性别:");
char gender = input.next().charAt(0);
System.out.println("姓名:" + name);
System.out.println("年龄:" + age + "岁");
System.out.println("体重:" + weight + "斤");
System.out.println("婚否:" + (marry ? "已婚":"未婚"));
System.out.println("性别:" + gender);
}
}
3.2 分支结构if-else
在实际生活中经常需要做出一些判断,比如开车来到一个十字路口,就需要对红绿灯进行判断,如果前面是红灯,就停车等候,如果是绿灯,就通行。Java中有一种特殊的语句叫做选择语句,它也需要对一些条件做出判断,从而决定执行哪一段代码。分支结构是指程序中出现了多种选择,即某些语句可能执行,可能不执行,是否执行要看条件是否满足。Java中的分支结构有两种:if系列的条件判断和switch系列的选择机构。
if系列的条件判断是通过布尔型的表达式或值进行条件判断的,最终选择执行一条路径,根据供选择路径的数量不同,if系列的条件判断可分为三种形式,即单分支、双分支和多分支。
3.2.1 单分支条件判断if
程序只有一个分支可选,条件成立就执行该对应的语句,不成立则不执行,如下图所示:
单分支条件判断if的语法如下:
if (条件表达式){
代码块
}
如果条件表达式成立(结果为true),则执行大括号中的语句块;如果不成立(结果为false),则跳过大括号中的语句块,直接执行语句块下的其他语句。
条件表达式的结果只能是布尔类型,支持以下几种形式:
布尔型的变量;
布尔型的常量;
布尔型的表达式,如关系表达式、逻辑表达式。
语句块可以有零条或多条语句组成,如果里面仅有一条,则可以省略大括号,示例:
if (a>b)
System.out.println("a>b")
注意:
如果语句块由多条语句组成,则不能省略大括号
示例:
public class Example07 {
public static void main(String[] args) {
int x = 5;
if (x < 10) {
x++;
}
System.out.println("x=" + x);
}
}
案例:2月份的总天数,用键盘输入一个年份值,输出该年2月份的总天数
import java.util.Scanner;
public class DaysOfFebruaryDemo{
public static void main(String[] args){
int dayOfFebruary = 28;
Scanner input = new Scanner(System.in);
System.out.print("请输入年份:");
int year = input.nextInt();
if ((year % 4 == 0 && year % 100 !=0) || year % 400 ==0) {
dayOfFebruary++;
}
System.out.println(year + "年的2月份有" + dayOfFebruary + "天");
}
}
3.2.2 双分支条件判断 if … else
双分支条件判断是在if判断的基础上增加与if判断条件表达式相反的代码执行块,这样就可以完成true、false的双向判断,并执行相应的代码执行块。
流程图如下所示:
双分支条件判断 if … else 语法如下:
if (条件表达式) {
语句块1;
} else {
语句块2;
}
可以发现两个if的条件是"非此即彼"的关系,此时可以使用一个承上启下的关键词"else",代表"否则",用于连接if条件不满足的情况下要执行的语句。
如果条件表达式成立(结果为true),则执行语句块1;如果条件表达式不成立(结果为false),则执行语句块2。
注意事项:
- 条件表达式必须是布尔表达式(关系表达式或逻辑表达式)、布尔变量或常量。
- 当语句块只有一条执行语句时,可以省略大括号,但建议保留。
案例:用键盘输入一个年份,判断是闰年还是平年。
import java.util.Scanner;
public class LeapYear{
public static void main(String[] args){
Scanner input = new Scanner(System.in);
System.out.print("请输入年份:");
int year = input.nextInt();
if ((year % 4 == 0 && year % 100 !=0) || year % 400 ==0){
System.out.println(year + "是闰年");
} else {
System.out.println(year + "是平年");
}
}
}
3.2.3 多分支条件判断 if … else if
除了双分支结构,程序还可以多条路径中选择一条去执行,也就是if …else if的基础上,增加多个条件表达式,判断这个表达式可以用else if完成,流程图如下:
多分支if … else if条件判断语法如下:
if (条件表达式1) {
语句块1;
} else if (条件表达式2) {
语句块2;
}
…
else {
语句块n;
}
如果条件表达式1成立,则执行语句块1, 否则继续判断条件表达式2,如果条件表达式2成立,则执行语句块2,依次类推,如果条件表达式都不成立,则执行else中的语句块n+1。
注意事项:
- 可以有多个else if 语句块;
- 单独的else语句块只能放在最后,不可以提到前面,该块是可选的。
示例:
根据输入的成绩判断成绩等级:
- 大于等于90分,优秀;
- 大于等于80分,小于90分,中等;
- 大于等于70分,小于80分,良;
- 大于等于60分,小于70分,及格;
- 小于60分,不及格。
public class Example09 {
public static void main(String[] args) {
int grade = 75; // 定义学生成绩
if (grade > 90) {
// 满足条件 grade > 90
System.out.println("该成绩的等级为优");
} else if (grade > 80) {
// 不满足条件 grade > 90 ,但满足条件 grade > 80
System.out.println("该成绩的等级为良");
} else if (grade > 70) {
// 不满足条件 grade > 80 ,但满足条件 grade > 70
System.out.println("该成绩的等级为中");
} else if (grade > 70) {
// 不满足条件 grade > 80 ,但满足条件 grade > 70
System.out.println("该成绩的等级为中");else {
// 不满足条件 grade > 60
System.out.println("该成绩的等级为差");
}
}
}
3.3 分支结构 switch-case
switch-case提供多分支程序结构语句。当多分支中的条件表达式是对同一个变量或表达式进行等值判断时,往往使用它代替实现。
3.3.1 分支结构 switch-case
switch语句好比是多路开关,流程图如下:
其语法结构如下:
switch(变量或表达式){
case 常量1;
语句1;
break;
case 常量2;
语句2;
break;
…
case 常量N:
语句N
default;
语句;
break;
}
swith结构的执行过程是先获取变量或表达式的值,然后从上往下依次匹配各个case后的常量值,判断是否与之相等。如果匹配成功,则执行case后的语句,直到遇见break或switch执行结束为止;如果匹配不成功,则执行default后的语句,直到遇见break或switch执行结束为止。
switch的执行特点有几个关键词:入口、出口、贯穿。
所谓入口,是指进入switch的某个分支开始执行,它有两种情况:
- 如果switch(变量或表达式)的值与某个case后面的常量值相匹配,那么就从这个case进入。
- 如果switch(变量或表达式)的值与所有case后面的常量值都不匹配,那么就从default进入。
所谓出口,是指一旦找到入口,switch结构可能从一个分支贯穿执行到下一个分支,直到遇到出口为止。无论是与case还是default匹配成功,在遇到break或switch结束大括号前,会一直贯穿向下执行,直到遇到出口为止。
注意事项:
- switch()中的变量或表达式的类型在JDK5前只能是int类型,或者int类型的兼容类型byte、short、char,在JDK5后开始支持枚举类型,在JDK7后开始支持Strin类型。
- case后只能是常量值,不能是变量或表达式。
- case后的常量值不能重复。
- case语句块中如果没有break,则将贯穿下面的case或default中的语句,不再判断是否相等。
示例:以下语句是否正确?如正确,输出结果是多少?
public class TestDefault{
public static void main(String[] args){
int x = 100;
int a = 2;
switch(a){
case 1:
x += 5;
default:
x += 34;
case 2:
x += 10;
case 3:
x += 16
}
System.out.println("x = " + x);
}
}
3.3.2 分支结构与条件判断的区别
- if语句和switch语句的比较:
- switch语句只支持常量值相等的分支判断,而if语句的支持更为灵活,任意的布尔表达式均可;
- switch语句通常比一系列嵌套if语句效率更高,逻辑更加清洗。
- if语句和switch语句的使用场景:
- switch语句建议用来判断固定值,且此时的固定值的取值范围不大;
- if语句建议用来判断区间或范围;
- switch语句能做的,if都能做,反之不行。
案例:用键盘分别输入年、月、日,判断这一天是当年的第几天。
import java.util.Scanner;
public class DaysOfYearDemo{
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();
System.out.print("日:");
int day = input.nextInt();
// 声明一个变量days,用来存储总天数
int days = 0;
// 累加[1, month-1]个月满月天数和第month月的day天
switch(month){
case 12:
days += 30; //11月
case 11:
days += 31; //10月
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月
if ((year % 4 == 0 && year % 100 !=0) || year % 400 == 0){
days++; //闰年多加一天
}
case 2:
days += 31; //1月
case 1:
days += day; //累加第month月的day天
}
System.out.println(year + "年" + month + "月" + day + "日是这一年的第" + days + "天");
}
}
3.4 循环结构
循环结构是指在某些条件满足的情况下,反复执行某段代码的结构。循环结构由循环条件来判断继续执行某个功能还是退出循环。
- 循环结构主要有以下三种形式:
- while语句;
- do while语句;
- for语句。
- 循环结构的四要素:
- 初始化表达式。循环变量的初始化表达式。
- 循环条件。反复执行代码所需的条件,必须是布尔型。如果是true,则执行循环体。如果是false,则跳出循环体。如果没有条件,或者条件恒成立,则为死循环。
- 循环体。反复执行的代码。
- 迭代表达式。循环变量值的修改,只有不断地修改循环变量的值,才会使循环终止。
3.4.1 while语句
while语句是一种先判断的循环结构,只要条件成立,就会执行大括号内的语句,直到条件不成立,while循环结束。流程图如下:
while语句循环条件的结果只能是布尔型的变量或值,这点和if语句的条件表达式相同。循环语句块如果只有一条语句,则可以省略大括号。
示例:打印100次“Hello World!”
public class TestWhile{
public static void main(String[] args){
int i = 1;
while (i <= 100){
System.out.println("Hello World!");
i++;
}
}
}
示例:趣味折纸,世界最高峰为珠穆朗玛峰,它的高度是8848.86米。假如我有一张足够大的纸,它的厚度是0.1毫米。请问我要对折多少次,才可以折成珠穆朗玛峰的高度?
public class PaperFolding{
public static void main(String[] args){
// 定义一个计数器,初始值为0
int count = 0;
// 定义纸张厚度
double paper = 0.1;
// 定义珠穆朗玛峰的高度;
int mountain = 8848860;
// 一直折叠,直到厚度达到珠穆朗玛峰的高度
while (paper <= mountain){
// 循环的执行过程中每次纸张折叠,
paper *= 2;
// 循环中执行累加,对应折叠了多少次
count++;
}
System.out.println("需要折叠:" + count + "次");
}
}
3.4.2 do … while语句
do … while语句实现的是先执行后判断的循环,没有入口条件,直接执行循环操作,再判断循环条件。总体来看,do …while语句大致同while语句,只是少了入口条件,do … while语句的执行流程如下图:
语法结构:
初始化表达式;
do {
循环体;
迭代表达式;
} while (循环条件);
示例:打印1~100的整数。
public class TestDoWhile{
public static void main(String[] args) {
int i = 1;
do {
System.out.println(i);
i++;
} while (i <= 100);
}
}
每个循环结构都应该具备循环4要素:
int i = 1; // 1.初始化表达式
do {
System.out.println(i); //3.循环体语句
i++; // 4.迭代表达式
} while (i <= 100); // 2.循环条件
while循环和do … while循环对比
示例:猜数字,随机生成一个[0, 100)以内的整数,然后猜这个数字是多少,如果用键盘输入的数大了,则提示猜大了,如果小了,则提示猜对了,并且结束。最后统计一共猜了多少次。
提示:系统函数Math.random()可以返回一个[0,1)范围的double值。
import java.util.Scanner;
public class GuessNumber{
public static void main(String[] args) {
int num = (int) (Math.random() * 100);
Scanner input = new Scanner(System.in);
int guess;
int count = 0;
do{
System.out.print("情输入[0, 100)的整数:");
guess = input.nextInt();
// 输入一次,就表示猜了一次
count++;
if (guess > num) {
System.out.println("猜大了!");
} else if (guess < num) {
System.out.println("猜小了!");
} else {
System.out.println("猜对了!");
}
} while (num != guess);
System.out.println("一共猜了:" + count + "次");
}
}
3.4.3 for语句
循环结构最开始设计的是while结构,即强调循环条件成立就执行语句,直到循环条件不成立。而引入do … while结构是为了满足至少执行一次循环体语句块的需求。但在这个使用过程中,有一种情况很常见,那就是循环条件是一个区间值,从几循环到几,每次修改循环变量的迭代语句也很有规律,为了满足这种需求,设计了for循环结构。for循环结构的执行流程如下图所示:
for循环语法结构:
for ( 1.循环变量初始化; 2.循环条件; 4.循环变量迭代更新表达式) {
3.循环体语句
}
说明:
- 两个分号必不可少,如果for括号中的三个表达式都省略,则相当于条件恒成立的"死循环"。
for ( ; ;) {
}
- 循环变量初始化可以由多条变量初始化语句组成,中间用逗号隔开。循环变量更新也可以由多条更新语句组成,中间用逗号隔开。
for (int i = 1, j=10; i <=10; i++, j--) {
}
- 循环条件部分为布尔型的表达式,当值为false时,退出循环。
案例:使用for循环结构打印1~100的整数
public class TestFor{
public static void main (String[] args) {
for (int i=1; i <= 100; i++) {
System.out.println(i);
}
}
}
3.4.4 嵌套循环
一个循环语句中又完整地嵌套了另一个循环语句,称为嵌套循环或多重循环,也就是一个循环结构的循环体也为循环结构。其中for、while、do … while均可以作为外层循环和内层循环。外层循环如果循环一次,内层循环则需要循环一轮。
案例:打印九九乘法表
public class MultiplicationTable{
public static void main(String[] args) {
for (int i = 1; i<=9; i++) {
for (int j = 1; j <= i; j++) {
System.out.print(j + "*" + i + "=" + (i * j) + "\t");
}
System.out.println();
}
}
}
3.5 跳转语句
跳转语句就是在中途改变程序原本的执行过程的语句。
3.5.1 break语句
break语句的意思是中断。break语句可以用于循环和switch结构,表示提前结束switch或当前循环。
示例:猜数字,随机生成一个[0, 100)以内的整数,然后猜这个数字是多少,如果用键盘输入的数大了,则提示猜大了,如果小了,则提示猜对了,并且结束。最后统计一共猜了多少次。
提示:系统函数Math.random()可以返回一个[0,1)范围的double值。
import java.util.Scanner;
public class GuessNumber1{
public static void main(String[] args) {
int num = (int) (Math.random() * 100);
Scanner input = new Scanner(System.in);
int guess;
int count = 0;
while (true) {
System.out.print("情输入[0, 100)的整数:");
guess = input.nextInt();
// 输入一次,就表示猜了一次
count++;
if (guess > num) {
System.out.println("猜大了!");
} else if (guess < num) {
System.out.println("猜小了!");
} else {
System.out.println("猜对了!");
break;
}
}
System.out.println("一共猜了:" + count + "次");
}
}
3.5.2 continue语句
continue语句的意思是继续。continue语句只能用在循环中,表示继续下一次循环,本次循环剩下的循环体语句将被跳出。
public class TestContinue{
public static void main(String[] args) {
int i = 1;
while (i <= 5) {
if (i == 3) {
continue; //死循环
}
System.out.println("Hello" + i);
i++;
}
}
}
案例:计算1~100之间能被3整除的数的和
public class TestThree{
public static void main(String[] args) {
int total = 0;
for (int i = 1; i <= 100; i++){
if (i % 3 != 0) {
continue;
} else {
total += i;
}
}
System.out.println("1~100能被3整除的数之和为:" + total);
}
}
3.5.3 return语句
return语句表示返回。return语句用在方法中的作用是结束所在方法。