流程控制


块作用域

学习流程控制之前,先来了解以下块作用域(即符合语句)是指由一对花括号括起来的若干条简单的 Java 语句。确定了变量的作用域。一个可以嵌套在另一个中。但是不能再嵌套的两个块中声明同名的变量:

public static void main(String[] args) {
    int n;
    ...
    {
        int k;
        int n;//错误,前面已经声明过变量 n 了
        ...
    }
}

条件语句

条件语句的格式为:

if (条件) 执行语句;

若要在某个条件为真时执行多条语句,则格式为:

if (条件) {
    执行语句 1
    执行语句 2
    ...
}

也可以在条件未达成时执行另一段语句:

if (条件) 执行语句 1 else 执行语句 2;

if (条件) {
    ...
} else {
    ...
}

else 部分是可选的,else 子句与最邻近的 if 构成一组,如下面代码中,else 与第二个 if 配对:

if (x <= 0) if (x == 0) sign = 0; else sign = -1;

当然,建议在写代码时即使执行条件只有一句,为了使代码更加清晰易懂,也建议加上花括号:

if (x <= 0) {
    if (x == 0) {
        sign = 0;
    } else {
        sign = -1;
    }
}

也可以重复地交替出现 if … else if … :

if (条件 1) {
    ...
} else if (条件 2) {
    ...
} else if (条件 3) {
    ...
} else {
    ...
}

## 循环语句 ### while 循环 **当条件为 true 时,while 循环执行一条语句(也可以是一个语句块):**
while (条件) 执行语句;

while (条件) {
    执行语句 1
    执行语句 2
    ...
}

需要循环的执行语句叫循环体。
while 循环语句首先检测循环条件,如果开始时,循环条件的值就为 false,则 while 循环体一次也不执行。

因此,循环体中的代码有可能不被执行。如果希望循环体至少执行一次,则需要使用 do/while 循环语句。


### do/while 循环 ## 语法格式:
do 执行语句 while (条件);

do {
    循环体
} while (条件);

do/while 循环语句限制性语句(通常是一个语句块),再检测循环条件;然后重复语句。

记得结尾加分号“;”


### for 循环 **for 循环又叫确定循环,for 循环语句是支持迭代的一种通用结构,利用每次迭代之后更新的计数器或类似的变量来控制迭代次数:**
for (初始化计数器; 计数器循环条件; 更新计数器) {
    循环体
}

for 的第一部分通常用于对计数器初始化;
第二部分给出每次新一轮循环执行前的条件(当然应该与计数器有关);
第三部分指示如何更新计数器。三部分用“;”隔开,例如:

for (int i = 1; i <= 10; i++) {
    System.out.println(i);
}
//之后将无法使用 i

该代码初始化一个计数器 i 的值为 1,循环判断 i 是否小于等于 10,只要 i 小于等于 10,就输出一次 i 的值,并且更新计数器 i 使其自增 1,直到 i 的值不再小于等于 10 的时候,循环结束。

for 循环的四个部分执行顺序如图:
for 循环流程图

  1. 初始化计数器
  2. 判断循环条件
  3. 循环体
  4. 更新计数器
  5. 回到第二步开始循环

在 for 循环第一部分声明的变量,其作用域为整个循环体,在循环体外无法使用该变量,若要在 for 循环体之外使用循环计数器,则需要在循环语句的前面且在外部声明:

int i;
for (i = 1; i <= 10; i++) {
    System.out.println(i);
}
//这之后可以继续使用 i

for 循环只是 while 循环的一种简化形式,如上述代码也可写成:

int i = 1;
while (i <= 10) {
    System.out.println(i);
    i++;
}

警告:
在循环中,检测两个浮点数是否相等时需要格外小心!如下面的 for 循环:

for (double x = 0; x != 10; x += 0.1) {
    ...
}

该循环永远不会结束。由于舍入的误差,无法得到精确值。该循环中,因为 0.1 无法精确地用二进制表示,所以,x 将从 9.999 999 999 999 98 跳到 10.099 999 999 999 98。


### for each 循环 **「for each 循环」又称「增强 for 循环」,可用来依次处理数组中的每个元素(其他类型的元素集合亦可)而不必为指定下标值而分心**,该循环的格式为:
for (声明变量 : 变量所属集合) 执行语句;

for (声明变量 : 变量所属集合) {
    循环体
}

该循环声明一个变量用于暂存集合中的每一个元素,并执行相应语句(或语句块),变量所属集合必须是一个数组或是一个实现了 Iterable 接口的类对象(例如 ArrayList),代码示例:

for (int i : a) {
    System.out.println(i);
}

打印数组 a 中的每一个元素,一个元素占一行,这种循环应读作“循环 a 中的每一个元素”。

该代码等同于:

for (int i = 0; i < a.length; i++) {
    System.out.println(i);
}

for each 循环语句的循环变量将会遍历数组中的每个元素,而不需要使用下标值。

因此,如果不希望遍历集合中的每个元素或者在循环内部需要使用下标值时还是要使用传统的 for 循环。


## 多重选择:switch 语句 在处理多个选项时,使用 if/else 结构会显得很笨拙,这时使用 switch 语句则会方便很多:
switch (选项值) {
    case 情况 1:
        ...
        break;
    case 情况 2:
        ...
        break;
    case 情况 3:
        ...
        break;
    default:
        ...
        break;
}

switch 语句将从与选项值相匹配的 case 标签处开始执行直到遇到 break 语句,或者执行到 switch 语句的结束处为止。如果没有相匹配的 case 标签,则会执行 default 子句,若也没有 default 子句,则直接结束 switch 语句。

有可能触发多个 case 分支。如果在 case 分支语句的末尾没有 break 语句,那么就会接着执行下一个 case 分支语句。这种情况相当危险,常常会因此引发错误,所以不推荐使用 switch 语句。

如果你确实想用这种“直通式”行为,可以为其外围方法加一个标注 @SuppressWarnings(“fallthrough”)。这样就不会对这个方法生成警告了。

case 标签可以是:

  • 类型为 char、byte、short 或 int (或者它们的包装器类: Character、Byte、Short 和 Inter)的常量表达式。
  • 枚举常量
  • JDK 7 及 以上 JDK 版本中的 case 标签还可以是字符串字面量。

## 中断控制流程语句 ### 不带标签的 break 语句 与用于退出 switch 语句的 break 语句一样,也可以**用于退出循环语句**:
while (years <= 100) {
    balance += payment;
    double interest = balance * interestRate / 100;
    balance += interest;
    if (balance >= goal) {
        break;
    }
    years ++;
}

该代码在循环开始时,如果 years > 100,或者在循环体中 balance >= goal,则结束循环语句。
上面的代码也可以在不使用 break 的情况下计算 years 的值:

while (years <= 100 && balance < goal) {
    balance += payment;
    double interest = balance * interestRate / 100;
    balance += interest;
    if (balance < goal) {
        years ++;
    }
}

但是,这样写会检测两次 balance < goal,为了避免重复检测,可以使用 break 语句


### 带标签的 break 语句 **带标签的 break 语句用于跳出多重嵌套的循环语句:**
Scanner in = new Scanner(System.in);
int n;
read_data://注意:标签必须放在希望跳出的最外层循环之前,并且必须紧跟一个冒号!
while (...) {
    ...
    for (...) {
        System.out.print("输入一个数字 >= 0: ");
        n = in.nextInt();
        if (n < 0) {
            break read_data;//跳出(结束) while 循环语句
        }
        ...
    }
}
//这里将在 break 后立即执行
if (n < 0) {
    解决你不想发生的情况
} else {
    正常执行的代码
}

可以将标签应用到任何语句中,甚至可以应用到 if 语句或者块语句中:

label:
{
    ...
    if (...) {
        break label;//结束块
    }
    ...
}
//如果执行了 break label 语句将直接跳到这里

注意:break 标签只能跳出语句块,不能跳入语句块。
并不提倡这种方式…


### continue 语句 **continue 语句用于将控制转移到最内层循环的首部(也就是跳出当前循环,继续下一次循环,而不是结束循环):**
Scanner in = new Scanner(System.in);
while (sum < goal) {
    System.out.print("输入一个数字:")
    n = in.nextInt();
    if (n < 0) {
        continue;
    }
    sum += n;//如果 n 小于 0 就不会执行这一步
}

如果 n < 0 则 continue 语句约过了当前循环体的剩余部分,直接开始下一次循环。

如果将 continue 语句用于 for 循环中,就会跳到 for 循环的“更新计数器”部分:

for (count = 1; count <= 100; count++) {
    System.out.print("输入一个数字,-1 则退出:");
    n = in.nextInt();
    if (n < 0) continue;
    sum += n;
}

该代码如果 n 小于 0,则 continue 语句直接跳转到 count++ 语句。


文章作者: CrazyBunQnQ
版权声明: 本博客所有文章除特別声明外,均采用 CC BY-NC 4.0 许可协议。转载请注明来源 CrazyBunQnQ !
 上一篇
面向对象(一) 面向对象(一)
面向对象程序设计简称 OOP 面向对象的程序是由对象组成的,每个对象包含对用户公开的特定功能部分和隐藏的实现部分。程序中的很多对象来自标准库,还有一些是自定义的。究竟是自己构造对象,还是从外界购买对象完全取决于开发项目的预算时间。在 OO
2017-02-28
下一篇 
运算符 运算符
类别 Java 运算符 算数运算符 + - * / % ++ – 扩展赋值运算符 += -= *= /= %= 比较运算符 > < >= <= == != 逻辑运算符 &&、丨
2017-02-23
  目录