Imagination i|

-Miao酱-

园龄:9个月粉丝:0关注:4

Java 流程控制语句(Control Flow)

选择意味着取舍——Miao酱

  • 程序设计中有三种流程结构,即:
    • 顺序结构
      • 程序从上到下逐行地执行,中间没有任何判断和跳转。
    • 分支结构
      • 根据判断条件,选择性地执行某段代码。
      • if…elseswitch-case两种分支语句。
    • 循环结构
      • 根据循环条件,重复性的执行某段代码。
      • forwhiledo-whileforeach四种循环语句。

1. 顺序结构

顺序结构很好理解,即程序从上到下逐行执行,直到最终结束。

public class StatementTest{
    public static void main(String[] args){
        int num1 = 1;
        int num2 = 2;
        int num3 = num1 + num2;
        System.out.println("num1 + num2 = " + num3);
    }
}

2. 分支结构(Conditional Statements)

分支结构也很好理解,类似于数学中的分类讨论,以解一元二次方程为例,当Δ>0时, 有两个不同的解,Δ=0时,有一个解,Δ<0时,方程无解。

2.1 if-else

2.1.1 基本语法

结构1:单分支条件判断:if

if(条件表达式){
    语句块;
}

eg. 高考成绩大于600分,则可以上985

import java.util.Scanner;
public class Test1{
    public static void main(String[] args){

        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入高考分数:");
        int score = scanner.nextInt();
        if (score >= 600){
            System.out.println("可以上985");
        }
        scanner.close();
    }
}

结构2:双分支条件判断:if...else

if(条件表达式) { 
    语句块1;
}else {
    语句块2;
}

eg. 判断一个整数是偶数还是奇数

import java.util.Scanner;
public class Test2{
    public static void main(String[] args){

        Scanner scanner=new Scanner(System.in);
        System.out.println("请输入一个整数:");
        int num=scanner.nextInt();

        if(num % 2 == 0) {
            System.out.println(num + "是偶数");
        } else{
            System.out.println(num + "是奇数");
        }
        scanner.close();
    }
}

结构3:多分支条件判断:if...else if...else

if (条件表达式1) {
    语句块1;
} else if (条件表达式2) {
    语句块2;
}
...
}else if (条件表达式n) {
    语句块n;
} else {
    语句块n+1;
}

eg. 小明参加期末Java考试,通过考试成绩,判断其Java等级,成绩范围[0,100]

  • 90-100 A
  • 80-89 B
  • 70-79 C
  • 60-69 D
  • 60以下 E
import java.util.Scanner;
//写法一:
public class Test3{
    public static void main(String[] args) {

        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入期末成绩:");
        int score = scanner.nextInt();

        if (score < 0 || 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 {
            System.out.println("你的成绩为 E");
        }
        scanner.close();
    }
}
import java.util.Scanner;
//写法二:
public class Test4{
    public static void main(String[] args) {

        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入期末成绩:");
        int score = scanner.nextInt();

        if (score < 0 || 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 {
            System.out.println("你的成绩为 E");
        }
        scanner.close();
    }
}

当条件表达式之间是互斥关系时,条件判断语句及执行语句间顺序无所谓。

当条件表达式之间是包含关系时,则按照“小上大下 / 子上父下”的顺序,否则范围小的条件表达式将不可能被执行。

2.2 switch-case

2.2.1 基本语法

switch(表达式){
    case 常量值1:
        语句块1;
        //break;
    case 常量值2:
        语句块2;
        //break; 
    // ...
[default:
        语句块n+1;
        break;
]
}

具体执行过程:

  1. 根据switch中表达式的值,依次匹配各个case。如果表达式的值等于某个case中的常量值,则执行对应case中的执行语句。

  2. 执行完此case的执行语句以后,
    ​ 情况1:如果遇到break,则执行break并跳出当前的switch-case结构
    ​ 情况2:如果没有遇到break,则会继续执行当前case之后的其它case中的执行语句。--->case穿透
    ​ ...
    ​ 直到遇到break关键字或执行完所有的case及default的执行语句,跳出当前的switch-case结构

注意

  • switch中表达式的值必须是下述几种类型之一:byte,short,char,int,枚举 (jdk 5.0),String (jdk 7.0);

  • case子句中的值必须是常量,不能是变量名或不确定的表达式值或范围;

  • 同一个switch语句,所有case子句中的常量值互不相同

  • break语句用来跳出switch语句块,如果没有break,程序会顺序执行到switch结尾;

  • default子句是可选的。同时,位置也是灵活的。当没有匹配的case时,执行default语句

错误举例:

// 判断是正数、负数、还是零
int key = 10;
switch(key){
    case key > 0 :
        System.out.println("正数");
        break;
    case key < 0:
        System.out.println("负数");
        break;
    default:
        System.out.println("零");
        break;
}

此种情况只能使用if-else语句进行条件判断

2.2.2 case的穿透性

案例1: 使用switch-case实现:对学生成绩大于60分的,输出“合格”。低于60分的,输出“不合格”。

public class SwitchCaseTest1{
    public static void main(String[] args) {
        
        int score = 67;
        /*
        写法1:极不推荐
        switch(score){
            case 0:
                System.out.println("不及格");
                break;
            case 1:
                System.out.println("不及格");
                break;
            //...
    
            case 60:
                System.out.println("及格");
                break;
            //...略...
        
        }
        */
    
        //写法2 利用case穿透
        switch(score / 10){
            case 0:
            case 1:
            case 2:
            case 3:
            case 4:
            case 5:
                System.out.println("不及格");
                break;
            case 6:
            case 7:
            case 8:
            case 9:
            case 10:
                System.out.println("及格");
                break;
            default:
                System.out.println("输入的成绩有误");
                break;
        }
    
        //写法3:
        switch(score / 60){
            case 0:
                System.out.println("不及格");
                break;
            case 1:
                System.out.println("及格");
                break;
            default:
                System.out.println("输入的成绩有误");
                break;
        }
    }
}

案例2: 从键盘上输入2024年的“month”和“day”,计算输入的日期为2024年的第几天。


import java.util.Scanner;

class SwitchCaseTest2{
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        System.out.println("请输入2024年的month:");
        int month = scan.nextInt();
        System.out.println("请输入2024年的day:");
        int day = scan.nextInt();
        int sumDays = 0;
        //利用case穿透
        switch(month){
            case 12:
                sumDays += 30;//这个30是代表11月份的满月天数
            case 11:
                sumDays += 31;//这个31是代表10月份的满月天数
            case 10:
                sumDays += 30;//这个30是代表9月份的满月天数
            case 9:
                sumDays += 31;//这个31是代表8月份的满月天数
            case 8:
                sumDays += 31;//这个31是代表7月份的满月天数
            case 7:
                sumDays += 30;//这个30是代表6月份的满月天数
            case 6:
                sumDays += 31;//这个31是代表5月份的满月天数
            case 5:
                sumDays += 30;//这个30是代表4月份的满月天数
            case 4:
                sumDays += 31;//这个31是代表3月份的满月天数
            case 3:
                sumDays += 29;//这个29是代表2月份的满月天数
            case 2:
                sumDays += 31;//这个31是代表1月份的满月天数
            case 1:
                sumDays += day;//这个day是代表当月的第几天
        }

        System.out.println(month + "月" + day + "日是2024年的第" + sumDays + "天");
        //关闭资源
        scan.close();
    }
}

2.2.3 if-else语句与switch-case语句比较

  • 凡是使用switch-case的结构都可以转换为if-else结构。反之,不成立。

  • 开发经验:如果既可以使用switch-case,又可以使用if-else,建议使用switch-case。因为效率稍高。

  • 细节对比:

    • if-else 语句优势
      • if语句的条件是一个布尔类型值,if条件表达式为true则进入分支,可以用于范围的判断,也可以用于等值的判断,使用范围更广
      • switch语句的条件是一个常量值(byte,short,int,char,枚举,String),只能判断某个变量或表达式的结果是否等于某个常量值,使用场景较狭窄
    • switch 语句优势
      • 当条件是判断某个变量或表达式是否等于某个固定的常量值时,使用if和switch都可以,习惯上使用switch更多。因为效率稍高。当条件是区间范围的判断时,只能使用if语句。
      • 使用switch可以利用穿透性,同时执行多个分支,而if...else没有穿透性。

3. 循环结构(Loops)

  • 循环结构分类:
    • for 循环
    • while 循环
    • do-while 循环
    • foreach 循环

3.1 for循环

3.1.1 基本语法

语法格式:

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

执行过程: ①-②-③-④-②-③-④-②-③-④-.....-②

说明:

  1. for(;;)中的两个;不能多也不能少。
  2. 初始化部分可以声明多个变量,但必须是同一个类型,用逗号分隔。
  3. 循环条件部分为boolean类型表达式,当值为false时,退出循环。
  4. 可以有多个变量更新,用逗号分隔。

3.2 while循环

3.2.1 基本语法

语法格式:

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

执行过程: ①-②-③-④-②-③-④-②-③-④-...-②

说明:

  1. while(循环条件)中循环条件必须是boolean类型。
  2. 不要忘记声明④迭代部分。否则,循环将不能结束,变成死循环。
  3. for循环和while循环可以相互转换。二者没有性能上的差别。
  4. for循环与while循环的区别:初始化条件部分的作用域不同。

3.3 do-while循环

3.3.1 基本语法

语法格式:

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

执行过程: ①-③-④-②-③-④-②-③-④-...-②

说明:

  1. 结尾while(循环条件)中循环条件必须是boolean类型
  2. do{}while();最后有一个分号
  3. do-while结构的循环体语句是至少会执行一次,这个和for和while是不一样的
  4. 循环的三个结构for、while、do-while三者是可以相互转换的。

3.4 对比三种循环结构

  • 三种循环结构都具有四个要素:

    • 循环变量的初始化条件
    • 循环条件
    • 循环体语句块
    • 循环变量的修改的迭代表达式
  • 从循环次数角度分析

    • do-while循环至少执行一次循环体语句
    • for和while循环先判断循环条件语句是否成立,然后决定是否执行循环体
  • 如何选择

    • 遍历有明显的循环次数(范围)的需求,选择for循环
    • 遍历没有明显的循环次数(范围)的需求,选择while循环
    • 如果循环体语句块至少执行一次,可以考虑使用do-while循环
    • 本质上:三种循环之间完全可以互相转换,都能实现循环的功能

案例:累加的思想

题目:遍历1-100以内的偶数,并获取偶数的个数,获取所有的偶数的和

// 写法一:for
public class ForTest{
    public static void main(String[] args) {
        int count = 0;// 记录偶数的个数
        int sum = 0;// 记录偶数的和

        for(int i = 1;i <= 100;i++){// 初始化、循环条件、迭代部分
            // 循环体
            if(i % 2 == 0){
                System.out.println(i);
                count++;
                sum += i;
            }
        }
        System.out.println("偶数的个数为:" + count);
        System.out.println("偶数的总和为:" + sum);
    }
}

// 写法二:while
public class WhileTest{
    public static void main(String[] args) {
        int num = 1;// 初始化部分
        int sum = 0;// 记录偶数和
        int count = 0;// 记录偶数的个数
    
        while(num <= 100){// 循环条件
            // 循环体
            if(num % 2 == 0){
                System.out.println(num);
                sum += num;
                count++;
            }
            // 迭代部分
            num++;
        }
        System.out.println("偶数的个数为:" + count);
        System.out.println("偶数的总和为:" + sum);
    }
}

// 写法三:do while
public class DoWhileTest{
    public static void main(String[] args) {
        int num = 1;// 初始化部分
        int sum = 0;// 记录偶数和
        int count = 0;// 记录偶数的个数

        do{
            // 循环体部分
            if(num % 2 == 0){
                System.out.println(num);
                sum += num;
                count++;
            }

            num++;// 迭代部分

        }while(num <= 100); // 循环条件部分
        System.out.println("偶数的总和为:" + sum);
        System.out.println("偶数的个数为:" + count);
    }
}

3.5 for each

for循环经常通过索引来遍历数组,但是我们实际想访问的是数组中的元素,故java提供了另一种循环,可以更加方便的便利数组。

public class ForEachTest{
    public static void main(String[] args) {
        int[] arr = { 1, 3, 5, 7, 9 };
        for (int n : arr) {
            System.out.println(n);
        }
    }
}

for each循环的变量n不再是计数器,而是直接对应到数组的每个元素。除了数组外,for each循环能够遍历所有“可迭代”的数据类型,例如List、Map等集合框架。

3.6 "无限"循环

语法格式:

  • while(true) , for(;;)

适用场景:

  • 开发中,有时并不确定需要循环多少次,需要根据循环体内部某些条件,来控制循环的结束(使用break)。
  • 如果此循环结构不能终止,则构成了死循环!开发中要避免出现死循环。

4. 关键字break & continue

4.1 break和continue的使用

在流程控制语句中,当程序满足某些条件时,如何才能提前结束流程控制语句,这就涉及到关键字break和continue的使用。具体如下:

  • break:结束或跳出当前的循环,适用范围为switch-case、循环结构
  • continue: 结束或跳出本次循环,适用范围为循环结构

举个例子:

// break
public class BreakTest1{
    public static void main(String[] args) {
        
        for (int i=1; i<=10; i++) {

            if (i % 5 == 0) {
                break; // break 通常搭配if使用,用于跳出当前循环
                // 当break跳出循环后,这行语句不会被执行,且编译器报错
                //System.out.println("#####"); 
            }
            System.out.println(i); // 1 2 3 4
        }      
    }
}

public class BreakTest2{
    public static void main(String[] args) {
        for (int i=1; i<=5; i++) {
            
            for (int j=1; j<=10; j++) {
                
                if (j % 5 == 0) {
                    break; // break跳出内循环
                }
                System.out.println("j = " + j);
            }
            
            // break跳到这里
            System.out.println("breaked");
        }
    }
}

// continue
public class ContinueTest1{
    public static void main(String[] args) {
        
        for (int i=1; i<=10; i++) {

            if (i % 5 == 0) {
                continue; // continue 通常搭配if使用,用于跳出本次循环
            }
            System.out.println(i); // 1 2 3 4 6 7 8 9
        } 
    }
}

4.2 带标签

当有多重循环时,break只能跳出最近的一层循环,那如何才可以跳出整个循环呢,我们可以使用label来实现。类似于goto语句,但是在java中却不允许使用(goto为保留字)。代码如下:

class BreakContinueTest{
    public static void main(String[] args) {
        label:for(int i = 1;i <= 4;i++){
        
            for(int j = 1;j <= 10;j++){
                if(j % 4 == 0){
                    //break label; // 123
                    continue label; // 123123123123
                }
                System.out.print(j);
            }
        }
    }
}
  • 标号语句必须紧接在循环的头部。标号语句不能用在非循环语句的前面。
  • continue语句出现在多层嵌套的循环语句体中时,也可以通过标签指明要跳过的是哪一层循环。

本文作者:喵酱

本文链接:https://www.cnblogs.com/miaotechisland/p/18634949

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   -Miao酱-  阅读(11)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起