控制流程
(一)块作用域
块(block)是指由一对大括号括起来的若干条简单的Java语句。块确定了变量的作用域。一个块可以嵌套在另一个块中。例如:
public static void main (String[] args){
int n;
...
{
int k;
...
} //k is only defined up to here
}
但是不能在嵌套的两个块中声明同名的变量,否则无法通过编译。
(二)条件语句
在Java中,条件语句的格式为:
if(condition) statement
我们常常希望在某个条件为真时,执行多条语句,这时就可以用到块语句(block statement)。
if(yourSales>=target){
performance = "Satisfactory";
bonus=100;
}
更一般的条件语句格式:
if(condition) statement1 else statement2
例如:
if(yourSales>=target){
performance ="Satisfactory";
bonus = 100+0.01*(yourSales-target);
}else{
performance = "Unsatisfactory";
bonus=0;
}
其中else部分是可选的。else字句与最邻近的if构成一组,下面看如下代码:
if(x<=0) if(x==0) sign=0;else sign=-1;
这个else应该与第二个if组成一组,使用大括号括起来会看得更加清楚,明显。
if(x<=0){
if(x==0){
sign=0;
}else{
sign=-1;
}
}
还有一种条件语句是if...else if...,示例如下:
if(yourSales>=2*target){
performance="Excellent";
bonus=1000;
}else if(yourSales>=1.5*target){
performance = "Fine";
bonus=500;
}else if(yourSales>=target){
performance="Satisfactory";
bonus=100;
}else{
System.out.println("You're fired");
}
(三)循环
当条件为true时,while循环执行一条语句,也可以是一个语句块(block),一般格式为:
while(condition) statement
如果开始循环条件的值为false,那么while循环体一次也不执行。
以下程序将计算需要多长时间才能存储一定数量的退休金,假定每年存入相同数量的金额,而且利率是固定的。
package CoreJava;
import java.util.Scanner;
/**
* This program demonstrates a <code>while<code> loop.
*
*/
public class Retirement {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
//read inputs
System.out.println("How much money do you need to retire?");
double goal = in.nextDouble();
System.out.println("How much money will you contribute every year?");
double payment = in.nextDouble();
System.out.println("Interset rate in %:");
double interestRate = in.nextDouble();
double balance = 0;
int year=0;
//update account balance while goal isn't reached
while(balance<goal) {
balance+=payment;
double interest = balance*interestRate/100;
balance+=interest;
year++;
}
System.out.println("You can retire in "+year+"years.");
}
}
在上面的程序中,我们看到循环体中来更新存款,并且添加了一个计数器(year)。
while循环是首先检测循环条件,所以循环体中的代码可能不会被执行。如果希望循环体至少执行一次,则应该讲检测条件放在最后,使用do/while循环可以实现这种操作方式:
do statement while(condition)
这种循环语句先执行语句,再检测循环条件,然后重复语句,再检测循环条件,以此类推。下面程序首先计算退休账户中的余额,然后再询问是否打算退休:
package CoreJava;
import java.util.Scanner;
/**
* This program demonstrates a <code>do/while<code> loop;
*
*/
public class Retirement2 {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
System.out.println("How many money will you contribute every year?");
double payment = in.nextDouble();
System.out.println("Interest rate in %:");
double interestRate = in.nextDouble();
double balance = 0;
int year =0;
String input;
do {
balance+=payment;
double interest = balance*interestRate/100;
balance+=interest;
year++;
System.out.printf("After year %d,your balance is %,.2f%n", year,balance);
System.out.println("Do you want to retire?(Y/N)");
input=in.next();
}while(input.equals("N"));
}
}
(四)确定循环
for循环语句是支持迭代的一种通用结构,利用每次迭代后更新计数器或类似的变量来控制迭代次数。例如:
for(int i=0;i<=10;i++){
System.out.println(i);
}
for循环第一部分通常用于对计数器的初始化,第二部分给出每次新一轮执行前要检测的循环条件,第三部分更新技术器。
警告:在循环中,检测两个浮点数是否相等需要格外小心,由于舍入误差,可能循环永远不会结束。
当在for语句的第一部分声明一个变量之后,这个变量的作用域就是整个循环体,特别注意,在循环体内部定义一个变量后,这个变量的作用域仅仅在循环体内,在循环体外部不能使用该变量。
for循环典型示例,用该程序来计算抽奖中奖的概率:
/**
* This program demonstrates a <code>for<code> loop;
*
*/
public class LotteryOdds {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
System.out.println("How many numbers do you need to draw?");
int k = in.nextInt();
System.out.println("What's the highest number you can draw?");
int n = in.nextInt();
int lotteryOdds = 1;
for(int i =1;i<=n;i++) {
lotteryOdds=lotteryOdds*(k-i+1)/i;
System.out.println(lotteryOdds);
}
System.out.println("Your odds are 1 in "+lotteryOdds+".Good luck!");
}
}
该程序原书中代码有误,应该将循环体内的n和k兑换位置,否则运行概率为0。
(五)多重选择:switch语句
在处理多个选项时,使用if/else显得有些笨拙,此事可以使用switch语句。例如有4个选项,则可以使用以下代码:
Scanner in = new Scanner(System.in);
System.out.println("Select an option(1,2,3,4)";
int choice = in.nextInt();
switch(choice){
case 1:
...
break;
case 2:
...
break;
case 3:
...
break;
case 4:
...
break;
default:
//bad input
...
break;
}
switch语句将从与选项值相匹配的case标签处开始执行,直到遇到break语句,或者执行到switch语句结束为止。如果没有与case相匹配的标签,那么久执行default。
警告:有可能触发多个分支,如果在case分支语句的末尾没有break语句,那么会接着执行下一个case分支语句,这种情况是相当危险的。为此,不建议使用switch语句。但是也可以加上标注@SuppressWarnings("fallthrough")。
case标签可以是:
①类型为char,byte,short,int的常量表达式
②枚举常量
③从JavaSE7开始,case标签还可以是字符串字面量
String input ="...";
switch(input.toLowerCase())
{
case "yes"://OK since Java SE7
...
break;
}
当在switch中使用枚举常量时,不必再每个标签中指明枚举名,可以由switch的表达式值确定。例如:
Size sz = ...;
switch(sz){
case SMALL://no need to use Size.SMALL
...
break;
}
(六)中断控制流程语句
尽管Java的设计者将goto作为保留字,但是实际上没有打算使用它。在某些时候也需要跳出循环,我们可以使用break语句。例如:
while(years<=100){
balance+=payment;
double interest = balance*interestRate/100;
balance+=interest;
if(balance>=goal){
break;
}
}
在Java中还提供了一种带标签的break,用于跳出多重嵌套的循环语句。这里用一个示例说明break语句的工作状态。请注意:标签必须放在所希望跳出的最外层循环之前,并且必须紧跟一个冒号。
Scanner in = new Scanner(System.in);
int n;
read_data:
while(...)//this loop statement is tagged with the label
{
...
for(...)//this inner loop is not labeld
{
System.out.println("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 excuted immediately after the labeled break
if(n<0)//check for bad situation{
//deal with bad situation
}else{
//carry out normal processing
}
事实上,可以将标签应用到任何语句中,甚至可以应用到if语句或者块语句中。
最后,还有一个continue语句,与break一样,它将中断正常的控制流程,continue将控制转移到最内层循环的首部。例如:
package CoreJava;
import java.util.Scanner;
/**
* This program demontrates <code>continue<code>;
*
*/
public class ContinueTest1 {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int sum=0;
int goal=100;
while(sum<goal){
System.out.println("Enter a number:");
int n = in.nextInt();
if(n<0) continue;
sum+=n;//not excuted if n<0;
}
}
}
如果将continue用于for循环中,就可以跳到for循环的更新部分。例如:
for(count=1;count<=100;count++){
n=in.nextInt();
if(n<0) continue;
sum+=n;//not excuted if n<0
//如果n<0,则continue语句跳转到count++语句
}
break和continue以及return的区别:break是跳出最外层循环体,不再执行循环;而continue是跳过单次循环,如果条件满足,循环还可以继续;return是结束方法,随之循环体也自然而然的结束。