【Java流程笔记】2-2 程序控制结构

§2-2 程序控制结构

Java 语言的结构主要有三种:顺序结构选择结构循环结构,这三种结构基本可以满足所有程序的运行要求。下面将对该三种结构展开描述。

2-2.1 顺序结构

Java 的基本结构就是顺序结构,是最简单的算法结构,除非特别指明,否则就按照顺序一句一句地执行。

语句和语句之间,程序框与程序框之间,都是自上而下的顺序执行的,它是由若干个依次执行的步骤组成的,是任何一个算法都离不开的基本算法结构

顺序结构可以用下图简单表示:

image

2-2.2 选择结构

在很多种情景下,我们需要对可能出现的各种结果作出不同回应,这时就需要针对不同情况做出选择。程序运行亦是如此,Java 的选择结构有ifswitch结构。

2-2.2.1 if单选择结构

语法

if (布尔表达式) {
    //当表达式结果为true时,执行语句
}

这种结构适用于判断一个东西是否可行,可行则执行if内语句,否则跳出判断。

举个例子:

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

        //if 单选择
        System.out.println("Please input: ");
        String s = scanner.nextLine();

        //equals.() 用于判断字符串内容是否相等
        if (s.equals("Hello")) {
            System.out.println(s);
        }
        System.out.println("END.");

        scanner.close();
    }
}

2-2.2.2 if双选择结构

语法

if (布尔表达式) {
    //条件满足时执行此语句
} else {
    //否则执行此语句
}

举个例子:

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

        //及格与不及格的判断:小于等于 60 分为不及格,60 分至 100 分为及格
        System.out.println("Please input the score: ");
        int score = scanner.nextInt();

        if (score <= 60) {
            System.out.println("Exam passed. ");
        } else {
            System.out.println("Exam failed. ");
        }

        scanner.close();
    }
}

2-2.2.3 if多选择结构

语法:可以添加多个else if,但执行时只会选择条件满足的一个执行,否则执行else后跳出结构。

if (布尔表达式) {
    //若该条件满足,执行该语句后跳出选择结构
} else if (布尔表达式) {
    //若该条件满足,执行该语句后跳出选择结构
} else if (布尔表达式) {
    //若该条件满足,执行该语句后跳出选择结构
} else {}

可以看到 2-2.2.2 例子所给的及格判断还有漏洞:若所输入的成绩不在 0 ~ 100 范围内该如何?同时欲给不同成绩分级该如何解决?

以下是解决方案:

public class IfDemo03 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        //判断所输入是否合法,并且分级
        double score = scanner.nextDouble();
        
        if (score >=0 && score < 60) {
            System.out.println("Exam failed. ");
        } else if (score >=60 && score < 70) {
            System.out.println("Level D");
        } else if (score >=70 && score < 80) {
            System.out.println("Level C");
        } else if (score >=80 && score < 90) {
            System.out.println("Level B");
        } else if (score >=90 && score < 100) {
            System.out.println("Level A");
        }else if (score == 100) {
            System.out.println("Full score! ");
        }else {
            System.out.println("Illegal score. ");
        }
        
        scanner.close();
    }
}

注意else if必须在else前,且多选择结构只会按顺序结构执行满足条件的语句执行,执行完后忽略其后的所有剩余else ifelse结构。

2-2.2.4 if嵌套结构

语法

if () {
    if () {}
}

if选择结构中再嵌套一个if选择结构也是合法的,利用这一点,我们来思考一个问题:

如何寻找一个1 - 100之间的数?

结合二分法,利用嵌套if结构,可以较快地解决这一问题。

2-2.2.5 switch多选择结构

多选择结构还有一个实现方法就是switch case语句。

switch case语句判断一个变量与一系列值中的某个值是否相等,每一个值称为一个分支。

语法

switch (expression) {
    case value:
        //语句
        break; //可选
    case value:
        //语句
        break; //可选
    //可接多个 case
    default: 	//可选
        //语句
}

注意:

  1. switch语句中的变量类型可以是byteshortintchar
  2. 从 Java SE 7 开始,switch支持字符串String类型;
  3. case标签必须为字符串常量或字面量。

下面来看一个例子:

public class SwitchDemo01 {
    public static void main(String[] args) {
        char grade = 'C';

        switch (grade) {
            case 'A':
                System.out.println("Excellent");
            case 'B':
                System.out.println("Great");
            case 'C':
                System.out.println("Good");
            case 'D':
                System.out.println("Almost there");
            case 'E':
                System.out.println("Oops!!");
            default:	//对于其他情况
                System.out.println("Unknown grades");
        }
    }
}

编译后运行,结果如图所示:

image

可以看到,当匹配到值C后,其后的两个case分支也都运行了,这种现象称为case 穿透,为防止这种现象发生,建议在每个case分支下加入break语句。修改后再运行,得到结果如图所示:

image

小提示:可以在文件资源管理器中将编译好的.class字节码文件拖入 IDEA 工程中,在 IDEA 中反编译.class文件。可以看到,若源文件使用了字符串和switch结构,可以看到字符串被转换成哈希值的过程(即所有的字符本质上都是数字)。

2-2.3 循环结构

我们有时会需要程序一直运行,基于这种需求,Java 内置了几种循环结构:while do...whilefor(JDK 5 加入)循环。

2-2.3.1 while循环

while循环是最基本的循环,语法

while (布尔表达式) {
    //循环内容
}

注意

  1. 只要布尔表达式的值为true循环就会一直进行
  2. 大多数情况下,我们需要让表达式失效以终止循环;
  3. 少部分循环需一直进行,如服务器请求监听等,这时候表达式可以为true
  4. 循环条件一直为true会导致程序陷入死循环(无限循环),正常情况下应避免死循环,否则会影响程序性能并导致程序崩溃死机。

2-2.3.2 do...while 循环

有时候我们也会希望程序在循环条件不满足的情况下也要至少执行一次,这时就需要使用do..while语句作循环了。

语法

do {
    //循环内容
}while (布尔表达式);

区别do...while语句是先执行,后判断;而while先判断,后执行。这可保证循环体至少被执行一次

举个例子:

public class DoWhileDemo01 {
    public static void main(String[] args) {
        int a = 0;

        while (a<0){
            System.out.println(a);
            a++;
        }
        System.out.println("==================");

        do {
            System.out.println(a);
        }while (a<0);
    }
}

编译后运行,得到结果如图:

image

可以看到,由于while先判断,条件不满足而跳过了该循环,而do...while即使在条件不满足的情况下仍至少执行了一次。这体现了 Java 的顺序结构

2-2.3.3 for循环

虽然所有循环结构都可以用whiledo...while表示,但 Java 提供了另一种语句 for,使得一些循环结构变得更加简单。

for语句是支持迭代的一种通用结构,是最有效最灵活的循环结构。for循环执行次数在执行前就已确定,语法

for (初始化变量;布尔表达式;更新迭代) {
    //代码语句
}

我们可以通过以下练习熟悉for语句:

练习 I :计算 0 到 100 之间奇数和与偶数和

利用for语句:

public class ForDemo01 {
    public static void main(String[] args) {
        //输出 0 到 100 的奇数和与偶数和

        int oddSum = 0;
        int evenSum = 0;

        for (int i = 0; i <= 100; i++) {
            //判断当前数是奇是偶
            if ( i % 2 !=0) {//取余运算
                oddSum+=i;
            }else {
                evenSum+=i;
            }
        }
        System.out.println("奇数和为"+oddSum);
        System.out.println("偶数和为"+evenSum);
    }
}

编译后运行,得下图结果:

image

练习 II:使用循环结构输出1 - 1000之间可被 5 整除的数,并且每行输出 3 个

使用for循环:

ublic class ForDemo02 {
    public static void main(String[] args) {
        for (int i = 0; i <= 1000; i++) {
            if ( i % 5 == 0) {
                System.out.print(i+"\t");
            }
            if (i % 15 == 0) {
                System.out.println();
            }
        }
    }
}

使用while循环:

public class WhileDemo02 {
    public static void main(String[] args) {
        int i = 0;  //初始化

        while ( i <= 1000){
            if ( i % 5 ==0) {
                System.out.print(i+"\t");
            }
            if ( i % 15 == 0) {
                System.out.println();
            }
            //循环体
            i++;    //更新迭代
        }
    }
}

练习 III:打印九九乘法表

public class ForDemo03 {
    public static void main(String[] args) {
        for (int i1 = 1; i1 <= 9; i1++) {
            for (int i2 = 1; i2 <= 9; i2++) {
                System.out.print(i1+" x "+i2+" = "+(i1*i2)+"\t");
            }
            System.out.println();
        }
    }
}

编译后运行,得到结果如图所示:

image

去掉重复项, i2 <= i1,有:

image

注意

  1. println会在每次输出后换行,而print不会换行

  2. for会先执行初始化步骤,可以声明一种类型,也可以初始化一个或多个循环控制变量,也可以是空语句;

  3. 然后检测布尔表达式的值,若为true,执行循环体,否则循环终止,执行循环体后面的语句;

  4. 执行一次循环后,更新循环控制变量(即控制迭代变量);然后再次检测布尔表达式的值,循环执行上述过程。

    for (;;) {
        //这是一个死循环
    }
    
  5. 在 IDEA 中,可用快捷方式快速创建for循环:

    例如:100.for会创建:

    for (int i = 0; i < 100; i++) {}
    

练习 IV:打印一个 5 行的等边三角形

public class TestDemo {
    public static void main(String[] args) {
        //打印一个三角形:5 行

        for (int i = 1; i <= 5; i++) {
            for (int j = 5; j >= i; j--) {
                System.out.print(" ");  //打印空白三角形
            }
            for (int j = 1; j <= i; j++) {
                System.out.print("*");  // 打印左半部分三角形
            }
            for (int j = 1; j < i; j++) {
                System.out.print("*");  //打印右半部分三角形
            }
            System.out.println();
        }
    }
}

在这里,我们需要分析这个问题的解决思路:

  1. 将打印的三角形补全为一个矩形;

  2. 以三角形底边中点为垂足,作出三角形的高,平分该矩形;

  3. 自此,打印内容至少被分割为三部分:左半部分空白三角形、左半部分非空白三角形和右半部分剩余三角形;

  4. 只需依次打印这些三角形即可。

    整理,如图所示:

    image

提示:当遇到较为难理解的地方时,可以在有疑惑的代码所在行行首单击设置断点(breakpoint),然后单击 Debug(或按下Shift + F9)开启调试,逐步查看程序中变量及其他的变化,以更好地查找问题。

2-2.3.4 for的增强用法

自从 Java SE 5 开始,引入了一种主要用于数组的增强型for循环。语法

for (声明语句:表达式) {
    //代码语句
}

举个例子:

public class ForDemo04 {
    public static void main(String[] args) {
        //定义一个数组
        int[] numbers = {10,20,30,40,50};

        //增强型 for 循环:创建新变量 x 用于遍历数组中每一个元素
        for (int x:numbers) {
            System.out.println(x);
        }

        System.out.println("=============================");

        //常规 for 循环:数组内元素下标从 0 开始
        for (int i = 0; i < 5 ; i++) {
            System.out.println(numbers[i]);     //将数组内第 i 个元素赋值于 i
        }
    }
}

两种情况运行结果一致:

image

2-2.4 breakcontinuegoto关键字

break在任何循环语句主题部分,均可用于控制循环的流程,用于强制退出循环,不执行循环中剩余的语句。(也可在switch中使用)

continue语句用在循环主体中,用于终止某次循环,即跳过循环体中尚未执行的语句,接着进行下一次是否执行循环的判定。

关于goto关键字

goto关键字很早就在设计语言中出现,尽管goto仍是 Java 的一个保留字,但尚未得到正式使用,也不推荐使用。Java 没有goto,然而,在breakcontinue这两个关键字身上,仍有一些goto的影子:带标签的breakcontinue

标签:后面跟着一个冒号的标识符,如label:

对 Java 来说唯一用到标签的地方是在循环语句之前,而在循环语句前设置标签的唯一理由是:我们希望在其中嵌套另一个循环,由于breakcontinue只中断当前循环,但若与标签使用,它们就会中断到标签存在的地方。

举个例子:

public class LabelDemo01 {
    public static void main(String[] args) {
        //求 101 - 150 的质数:
        int count = 0;

        outer:for (int i = 101; i < 150;i++) {
            for (int j = 2; j < i/2 ; j++) {
                if (i % j == 0) {
                    continue outer;
                }
            }
            System.out.print(i+"  ");
        }
    }
}

但这种写法不建议使用

因为goto关键字可以让程序毫无条件地跳转到任意想要执行的区块上,这种写法在编写大型程序中往往显得不易于维护,也不易于追踪程序运行的逻辑顺序,容易使程序结构混乱。但是,合理使用goto关键字,可以提升程序可读性,这种情况是建立在禁止滥用goto关键字的前提上的。

posted @ 2021-07-21 23:57  Zebt  阅读(145)  评论(0)    收藏  举报