3.8 控制流程
注释:Java的控制流程结构与C/C++的控制流程结构一样,只有很少的例外情况.没有goto语句,但 break 语句可以带标签,可以利用它实现从内存循环跳出的目的(这种情况下C语言采用goto语句实现).另外还有一种变形的 for 循环,在C/C++中没有,它有点类似C#中的 for each循环.3.8.1 块作用域
块(即复合语句)是指由一对花括号括起来的若干条简单的Java语句.块确定了变量的作用域.不能再嵌套的两个块中声明同名的变量.例如下面的代码就有错误,无法通过编译:
public static void main(String[] args)
{
int n;
...
{
int k;
int n; // error!!! can't redefine n in inner block
...
}
}
注释:在C++中,可以在嵌套的块中重定义一个变量(详见这里).在内层定义的变量会覆盖在外层定义的变量.这样有可能会导致程序设计错误,因此在Java中不允许这样做.
3.8.2 条件语句
在Java中,条件语句的格式为:if (condition)
statement
或
if (condition)
{
statement1;
statement2;
}
或
if (condition)
statement1;
else
statement2;
其中 else 子句与最邻近的 if 构成一组.
3.8.3 循环
常用的格式为:while (condition)
statement;
while 循环语句首先检测循环条件,因此,循环体中的代码有可能不执行.
如果希望循环体至少执行一次,则应该将检测跳放在最后.使用 do/while 可以实现这种操作方式:
do
statement
while (condition);
Retirement.java如下所示:
import java.util.*;
public class Retirement
{
public static void main(String[] args)
{
// read inputs
Scanner in = new Scanner(System.in);
System.out.print("how much money do you need to retire?");
double goal = in.nextDouble();
System.out.print("how much money will you contribute every year?");
double payment = in.nextDouble();
System.out.print("Interest rate in %:");
double interestRate = in.nextDouble();
double balance = 0;
int years = 0;
// update account balance while goal isn't reached
while (balance < goal)
{
// add this year's payment and interest
balance += payment;
double interest = balance * interestRate / 100;
balance += interest;
years++;
}
System.out.println("You can retire in " + years + " years.");
}
}
Retirement2.java如下所示:
import java.util.*;
public class Retirement2
{
public static void main(String[] args)
{
Scanner in = new Scanner(System.in);
System.out.print("how much money will you contribute every year?");
double payment = in.nextDouble();
System.out.print("Interest rate in %: ");
double interestRate = in.nextDouble();
double balance = 0;
int year = 0;
String input;
// update account balance while user isn't ready to retire
do
{
// add this year's payment and interest
balance += payment;
double interest = balance + interestRate / 100;
balance += interest;
year++;
// print current balance
System.out.printf("After year %d, your balance is %,.2f%n", year, balance);
// ask if ready to retire and get input
System.out.print("Ready to retire?(Y/N) ");
input = in.next();
}
while (input.equals("N"));
}
}
3.8.4 确定循环
for 循环语句是支持迭代的一种通用结构,利用每次迭代之后更新的计数器或类似的变量来控制迭代次数.for (int i; i <= 10; i++)
System.out.println(i);
for 语句的
第1部分通常用于对计数器初始化;第2部分给出每次新一轮循环执行前要检测的循环条件;第3部分指示如何更新计数器.
Java中 for 语句的3个部分应该对同一个计数器变量进行初始化,检测和更新.
警告:在循环中,检测两个浮点数是否相等需要格外小心.下面的 for 循环
for (double x= 0; x != 1.0; x += 0.1)
可能永远不会结束,由于舍入的误差,最终可能得不到精确地值.
LotteryOdds.java如下所示:
import java.util.*;
public class LotteryOdds
{
public static void main(String[] args)
{
Scanner in = new Scanner(System.in);
System.out.print("how many numbers do you need to draw?");
int k = in.nextInt();
System.out.print("what is the highest number you can draw?");
int n = in.nextInt();
int lotteryOdds = 1;
for (int i = 1; i < k; i++)
lotteryOdds = lotteryOdds * (n - i + 1) / i;
System.out.println("Your odds are 1 in " + lotteryOdds + ". Good luck!");
}
}
3.8.5 多重选择:switch 语句
switch 语句将从与选项值相匹配的 case 标签处开始执行直到遇到 break 语句,或者执行到 switch 语句的结束处位置.如果没有相匹配的 case 标签,而有 default 子句,就执行这个子句.警告:有可能触发多个 case 分支.如果在 case 分支语句的末尾没有 break 语句,那么就会接着执行下一个 case 分支语句.
3.8.6 中断控制流程语句
Java语言中增加一条带标签的 break,以支持 goto 跳出循环的风格.下面首先看一下不带标签的 break 语句.与用于退出 switch 语句的 break 语句一样,它也可以用于退出循环语句.例如:
while (year <= 100)
{
balance += payment;
if (balance >= goal)
break;
years++;
}
在循环开始时,如果years > 100,或者在循环体中balance >= goal,则退出循环语句.
与C++不同,Java还提供了一种带标签的 break 语句,用于跳出多重嵌套的循环语句.
注意,标签必须放在希望跳出的最外层循环之前,并且必须紧跟一个冒号.
Scanner in = new Scanner(System.in);
int n;
read_data:
while (...)
{
...
for (...)
{
System.out.print("Enter a number >= 0: ");
n = in.nextInt();
if (n < 0) // should never happen-can't go on
break read_data;
// break out of read_data loop
...
}
}
// this statement is executed immediately after the labeled break
if (n < 0) // check for bad situation
{
// deal with bad situation
}
else
{
// carry out normal processing
}
如果输入有误,通过执行带标签的 break 跳转到带标签的语句块末尾.
对于任何使用 break 语句的代码都需要检测循环是否正常结束,还是由 break 跳出.continue 语句 break 语句一样,它将中断正常的控制流程. continue 语句将控制转移到最内层循环的首部.