解读Java中的流程控制

本文详细介绍了程序设计中的流程控制语句,包括顺序结构、选择结构(if-else、switch-case)和循环结构(for、while、do-while)。通过实例展示了它们在Java中的应用,如数字排序、彩票匹配规则判断以及日期计算等。此外,还讨论了break和continue的使用以及循环嵌套,并提供了跳出指定循环的标签使用方法。
摘要由CSDN通过智能技术生成

流程控制语句是用来控制程序中各语句执行顺序的语句,可以把语句组合成能完成一定功能的小逻辑模块。

流程控制方式采用结构化程序设计中规定的三种基本流程结构:

  • 顺序结构
  • 选择结构
  • 循环结构

顺序结构

顺序结构:程序从上到下逐行地执行,中间没有任何判断和跳转。
image-20210402185221790

一个简单应用:Java中定义成员变量时采用合法的前向引用,即变量先定义再使用


选择结构

选择结构:根据条件,选择性地执行某段代码。有if…else和switch-case两种分支语句。

if-else结构

if语句有三种形式:

结构一:

if(条件表达式){
	执行代码块;
}

流程图如下:
image-20210402185925609

结构二:

if( 条件表达式){
	执行代码块1;
}else{
	执行代码块2;
}

流程图如下:

image-20210402190137279

结构三:

if(条件表达式1){
	执行代码块1;
}else if (条件表达式2){
	执行代码块2;
}
……
else{
	执行代码块n;
}

流程图如下:

image-20210402190415422

if-else使用说明:

  • 条件表达式必须是布尔表达式,即最终结果都必须等价于true或者false
  • 当if-else结构是“多选一”时,最后的else是可选的,根据需要可以省略
  • 执行代码块只有一条执行语句时,一对{}可以省略,但建议保留,提高代码的可读性
  • if-else结构可以嵌套使用。if嵌套时,如果没有{},else 与 if 的配对满足就近原则,即else与最近的一个if配对,比较容易出错
  • 关于多选一时条件表达式的声明顺序:
    • 当多个条件是“互斥”关系时,条件判断语句及执行语句的声明顺序无所谓
    • 当多个条件是“包含”关系时,通常情况下,需要将范围小的声明在范围大的上面。反之,先范围大的,范围小的是没有机会执行的
    • 当多个条件是有交集关系时,根据具体的情况,酌情考虑声明的顺序

例子:

/*
由键盘输入三个整数分别存入变量num1、num2、num3,
对它们进行排序(使用if-else结构),并且从小到大输出
 */
public class IfTest01 {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        System.out.println("请输入第一个整数:");
        int num1 = scanner.nextInt();
        System.out.println("请输入第二个整数:");
        int num2 = scanner.nextInt();
        System.out.println("请输入第三个整数:");
        int num3 = scanner.nextInt();
        //3个数排序一共6种情况,两层嵌套的话就是每层里面有三个子层
        if(num1 >= num2){
            if(num3 >= num1){
                System.out.println(num2 + "," + num1 + "," + num3);
            }else if(num3 <= num2){
                System.out.println(num3 + "," + num2 + "," + num1);
            }else {
                System.out.println(num2 + "," + num3 + "," + num1);
            }
        }else {
            if(num3 >= num2)
                System.out.println(num1 + "," + num2 + "," + num3);
            else if(num3 <= num1)
                System.out.println(num3 + "," + num1 + "," + num2);
            else 
                System.out.println(num1 + "," + num3 + "," + num2);
            
        }

    }

}
/*
程序随机地产生一个两位数的彩票,提示用户输入一个两位数,
然后按照下面的规则判定用户是否能赢。
1)如果用户输入的数匹配彩票的实际顺序,奖金10000美元。
2)如果用户输入的所有数字匹配彩票的所有数字,但顺序不一致,奖金3000美元。
3)如果用户输入的一个数字仅满足顺序情况下匹配彩票的一个数字,奖金1000美元。
4)如果用户输入的一个数字仅满足非顺序情况下匹配彩票的一个数字,奖金500美元。
5)如果用户输入的数字没有匹配任何一个数字,则彩票作废。

 */
public class IfTest02 {

    public static void main(String[] args) {
        // Math.random()产生[0.0,1.0)的数
        //两位整数的范围是[10,100)
        int randNum = (int)(Math.random()*90 + 10);
        //分别取出随机数的个位和十位
        int randLow = randNum % 10;
        int randHigh = randNum / 10;
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入一个两位整数:");
        int inputNum = scanner.nextInt();
        //分别取出输入数据的个位和十位
        int inputLow = inputNum % 10;
        int inputHigh = inputNum / 10;
        //题目中的顺序已经是合理的顺序,依照要求编写即可
        //顺序一致,数字全部一致
        if(randNum == inputNum){
            System.out.println("奖励10000美元");
            //顺序不一致,数字全部一致
        }else if (randLow == inputHigh && randHigh == inputLow){
            System.out.println("奖励3000美元");
            //顺序一致,只有一个数字相同
        }else if (randHigh == inputHigh || randLow == inputLow){
            System.out.println("奖励1000美元");
            //顺序不一致,只有一个数字相同
        }else if (randHigh == inputLow || randLow == inputHigh){
            System.out.println("奖励500美元");
        }else {
            System.out.println("没有奖励");
        }
        System.out.println("彩票的号码是:" + randNum);

    }

}

switch-case结构

格式如下:

switch(表达式){
	case 常量1:
	语句1;
	// break;
	case 常量2:
	语句2;
	// break;
	… …
	case 常量N:
	语句N;
	// break;
	default:
	语句;
	// break;
}

流程图如下:
image-20210410132620663

switch-case使用说明:

  • switch-case的作用:根据switch表达式中的值,依次匹配各个case中的常量。一旦匹配成功,则进入相应case结构中,调用其执行语句。当调用完执行语句以后,则仍然继续向下执行其他case结构中的执行语句,直到遇到break关键字或此switch-case结构末尾结束为止。

  • switch(表达式)中表达式的值 必须是下述几种类型之一:byte ,short,char ,int, 枚举 (jdk5以后更新) ,String (jdk7以后更新)

  • case子句中的值必须是常量,不能是不确定的表达式值或者未赋值的变量, 且同一个switch语句,所有case子句中的常量值互不相同

  • break是可选的,一旦执行到break,则跳出switch-case结构

  • default子句是可选的的。同时,位置也是灵活的。当没有匹配的case时,执行default。相当于if-else中的else

  • 因为break可选,所以当多个case的执行语句相同时,可以考虑“合并”。因为case后面的值不同,所以只会执行其中一个,只需在末尾的case中写一个break即可。

来个小例题:

/*
从键盘分别输入年、月、日,判断这一天是当年的第几天,使用switch-case结构完成
注:判断一年是否是闰年的标准:
1)可以被4整除,但不可被100整除
 或
2)可以被400整除
*/
public class SwitchTest01 {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入year:");
        int year = scanner.nextInt();
        System.out.println("请输入month:");
        int month = scanner.nextInt();
        System.out.println("请输入day:");
        int day = scanner.nextInt();

        //定义一个变量保存天数
        int sumDays = 0;

        /*这里月份如果不倒序写就会出现:
            sumDays = sumDays + 31 + 29 + 31 + ... + 31这种冗余的情况
            不写break,根据月份依次加天数
         */
        switch(month){
            case 12:
                sumDays += 31;
            case 11:
                sumDays += 30;
            case 10:
                sumDays += 31;
            case 9:
                sumDays += 30;
            case 8:
                sumDays += 31;
            case 7:
                sumDays += 31;
            case 6:
                sumDays += 30;
            case 5:
                sumDays += 31;
            case 4:
                sumDays += 30;
            case 3:
                sumDays += 31;
            case 2:
                //判断是否是闰年
                if((year%4 == 0 && year%400 != 0) || year%400 == 0){
                    sumDays += 29;
                }else {
                    sumDays += 28;
                }
            case 1:
                sumDays += day;
        }

        System.out.println("这一天是"+ year + "的第" + sumDays + "天");

    }

}

switch和if语句的对比(应用场景):

  • 如果判断的具体数值不多,而且符合byte、short 、char、int、String、枚举等几种类型。虽然两个语句都可以使用,建议使用swtich语句。因为效率稍高。
    为啥switch效率比if-else高?
if(a==1){
}
else if(a==2){    
}
else if{    
}
...

如上代码所示,每次进行if判断时寄存器都要读取一次a的值,寄存器并不知道我们判断的是同一个值。而switch-case语句只需要读取一次。

  • 其他情况:对区间判断,对结果为boolean类型判断,使用if,if的使用范围更广。也就是说,使用switch-case的,都可以改写为if-else。反之不成立。

循环结构

所谓循环结构是在某些条件满足的情况下,反复执行特定代码的功能。

有while、do-while、for三种循环语句。

循环语句通常有四个组成部分:

  1. 初始化部分(init_statement)
  2. 循环条件部分(test_exp)
  3. 循环体部分(body_statement)
  4. 迭代部分(alter_statement)

for循环

语法格式:

for(①初始化部分;②循环条件部分;④迭代部分){
    ③循环体部分;

执行过程:

①-②-③-④-②-③-④-②-③-④-…-②(循环条件不再满足,循环结束)

for循环的说明:

  1. 循环条件部分为boolean类型表达式,当值为false时,退出循环
  2. 初始化部分可以声明多个变量,但必须是同一个类型,用逗号分隔;迭代部分可以有多个变量更新,用逗号分隔
  3. 这里循环语句的四个部分都不是必需的,可以不写,但是容易因少些条件形成死循环,不建议这么做

while循环

语法格式:

①初始化部分
while(②循环条件部分){
    ③循环体部分;
    ④迭代部分;  //循环体部分和迭代部分顺序可以交换
}

执行过程:

①-②-③-④-②-③-④-②-③-④-…-②

while循环的说明:

  1. 不要忘记声明④迭代部分。否则,循环将不能结束,变成死循环。
  2. for循环和while循环可以相互转换,观察执行过程可以发现和for循环是一致的。
  3. while循环中只有循环条件部分是必须写的
//for与while相互转换,注意迭代条件的顺序
int i = 1;
while (i < 10){
    i++;
    System.out.println("i=" + i);
}
//**************************************
for (int j = 1; j < 10; ) {
    j++;
    System.out.println("j=" + j);
}

do-while循环

语法格式:

①初始化部分;
do{
    ③循环体部分;
    ④迭代部分; //循环体部分和迭代部分顺序可以交换
}while(②循环条件部分);

执行过程:

①-③-④-②-③-④-②-③-④-…-②

do-while循环的说明:

  1. do-while循环至少执行一次循环体
  2. do-while中也只有循环条件部分时必须写的

来个小例题:

输入两个正整数m和n,求其最大公约数和最小公倍数。

public class Test01 {

    public static void main(String[] args){
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入正整数m:");
        int m = scanner.nextInt();
        System.out.println("请输入正整数n:");
        int n = scanner.nextInt();

        //求最大公约数
        //最大公约数的最大值就是m,n中较小的值(m % n==0),所以从大到小开始遍历
        for (int i = (m>n) ? n:m; i >= 1 ; i--) {
            //是否能除尽
            if(m % i == 0 && n % i == 0){
                System.out.println("最大公约数i为:" + i);
                break;
            }
        }

        //求最小公倍数
        //最小公倍数最小值是mn中较大的数,mn存在倍数关系
        int j = (m>n) ? m:n;
        //最小公倍数的最大值是m*n,mn不存在倍数关系,且没有公约数
        while (j <= m*n){
            if (j % m == 0 && j % n == 0){
                System.out.println("最小公倍数j为:" + j);
                break;
            }
            j++;
        }

    }

}	
  

循环嵌套

将一个循环放在另一个循环体内,就形成了嵌套循环。其中,for ,while ,do-while均可以作为外层循环或内层循环。

实质上,嵌套循环就是把内层循环当成外层循环的循环体。当只有内层循环的循环条件为false时,才会跳出内层循环,才可结束外层的当次循环,开始下一次的外层循环。

设外层循环次数为m次,内层为n次,则内层循环体实际上需要执行m*n次。

举个简单的应用就是输出九九乘法表:

1*1 = 1  
2*1 = 2  2*2 = 4  
3*1 = 3  3*2 = 6  3*3 = 9  
4*1 = 4  4*2 = 8  4*3 = 12  4*4 = 16  
5*1 = 5  5*2 = 10  5*3 = 15  5*4 = 20  5*5 = 25  
6*1 = 6  6*2 = 12  6*3 = 18  6*4 = 24  6*5 = 30  6*6 = 36  
7*1 = 7  7*2 = 14  7*3 = 21  7*4 = 28  7*5 = 35  7*6 = 42  7*7 = 49  
8*1 = 8  8*2 = 16  8*3 = 24  8*4 = 32  8*5 = 40  8*6 = 48  8*7 = 56  8*8 = 64  
9*1 = 9  9*2 = 18  9*3 = 27  9*4 = 36  9*5 = 45  9*6 = 54  9*7 = 63  9*8 = 72  9*9 = 81  
for (int i = 1; i <= 9; i++) {
   for (int j = 1; j <= i ; j++) {
       System.out.print(i + "*" + j + " = " + i*j + "  ");
   }
   System.out.println();
}

以外层循环控制行数,内层循环控制列数

关键字break和continue的使用

关键字使用范围作用
breakswitch-case,循环结构终止switch-case,结束当前循环
continue循环结构结束当次循环

这里如何去理解“当前”和“当次”呢?

先体验一下:

for (int i = 1; i <= 7; i++) {
    if(i % 4 == 0){
         break;
         //continue;
         //System.out.print(i); 这里的语句并不会得到执行
     }
     System.out.print(i);
}

如果使用break,输出的结果为:123

如果使用continue,输出结果为:123567

由此可见break是直接结束整个循环语句块,而continue只是跳过其所在循环语句块的一次执行,继续下一次循环

注意: break、continue之后不能有其他的语句(同一对{}之内),因为程序永远不会执行其后的语句。

那么有多层循环时,我们如何跳出指定的循环呢?

可以通过使用一个标签来实现:

 label:for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 4; j++) {
                if(j == 2){
                    System.out.println(j);
                    break label;
                    //continue label;
                }
            }
 }

这里就可以直接跳出外层循环了。

内层循环也可以使用:

for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 4; j++) {
                label:if(j == 2){
                    System.out.println(j);
                    break label;
                    //continue label;
                }
            }
 }

此时跳出内层循环,但是一般内层循环没必要使用标签。

这里label的使用相当于:

for (int i = 0; i < 4; i++) {
            label:for (int j = 0; j < 4; j++) {
                if(j == 2){
                    System.out.println(j);
                    break label;
                    //continue label;
                }
            }
 }

注意:

  • 标签只要满足标识符的命名规则即可

  • break和continue都可以使用标签,一般对break使用

  • 标签必须紧接在循环语句块的头部,不能对非循环语句块使用

    //错误使用
    label:int i = 1; 
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 4; j++) {
            if(j == 2){
                System.out.println(j);
                break label;
            }
        }
    }
    

总结:

  1. 三种循环结构的表达方式基本是一致的,没有什么明显的区别

  2. 几种无限循环的使用方式:while(true),for( ; ; )…

  3. 循环可以嵌套使用

  4. 结束循环的方式有break和continue,可以使用标签跳出指定循环

来个典型的题目:

输出100以内的质数(质数是指在大于1的自然数中,除了1和它本身以外不再有其他因数的自然数)

简单分析一下:

需要两层循环,外层遍历,内层判断。

判断是否是质数不需要将小于该数的所有数都除一遍,只需要除到该数的开方即可。

public static void printPrimerNumber(){
        //定义一个标签,判断是否是质数
        boolean flag;
        //外层循环遍历2~100的自然数
        for (int i = 2; i <= 100; i++) {
            flag = true;
            //内层循环进行判断是否为质数,在范围内如果就被1以外的数除尽,那么就不是质数,没必要再进行计算,直接判断下一个数
            for (int j = 2; j <= Math.sqrt(i); j++) {
                if(i % j == 0){
                    flag = false;
                    break;
                }
            }
            if (flag){
                System.out.println(i);
            }
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值