首页 > 代码库 > (翻译)《二》语言基础(4)--控制流语句
(翻译)《二》语言基础(4)--控制流语句
控制流语句
代码中的语句通常都是自上而下顺序执行。但是控制流语句打断执行的流程,利用决策、循环、分支,让你的程序有条件的执行代码的某一部分。本节描述java支持的决策语句(if-then,if-then-else,switch),循环语句(for,while,do-while),分支语句(break,continue,return)。
if-then和if-then-else语句
if-then是控制流语句中最基础的。它告诉你的程序执行某段代码,当某个特定的条件为真时。比如,Bicycle类会允许刹车降低自行车的速度,只有当自行车还在运动中。applyBrakes方法可能的实现如下:
void applyBrakes(){
if(isMoving){
currentSpeed--;
}
}
如果条件为false(自行车没有移动),跳过if-then语句。
此外,如果只有一条语句,大括号是可选的。
void applyBrakes(){
if(isMoving)
currentSpeed--;
}
是否要省略大括号根据个人的风格。不过省略大括号使代码更脆弱。如果后面会在then分支中增加语句,一个常见的错误是忘记增加对应的大括号。编译器无法发现这类错误,你因此将会得到一个错误的结果。
if-then-else语句提供了另外的路径来执行,当if从句的结果是false。你可以在applyBrakes方法中使用if-then-else语句来执行一些动作,如果自行车在没有运动时使用刹车。本例中,将会打印一些错误信息说明自行车已经停下。
void applyBrakes(){
if(isMoving){
currentSpeed--;
}else{
System.err.println("bicycle has already stopped.");
}
}
下面程序,根据得分分配等级,大于90是A,大于80是B,大于70是C,大于60是D,其他是F。
class IfElsedemo{
public static void main(String[] args){
int testScore = 79;
char grade;
if(testScore >= 90){
grade = ‘A‘;
}else if(testScore >= 80){
grade = ‘B‘;
}else if(testScore >= 70){
grade = ‘C‘;
}else if(testScore >= 60){
grade = ‘D‘;
}else {
grade = ‘F‘;
}
System.out.println("grade is " + grade);
}
}
输出为C。
你也许注意到testScore的值满足混合语句中不止一条表达式:79>70;79>60。但是当一个条件满足,那么对应的语句就会执行(grade = ‘C‘),剩下的条件语句就不会执行了。
switch语句
不像if-then和if-then-else语句,switch语句可以有很多可以执行的路径。switch和byte、short、int、char基础数据类型工作。它也可以和枚举类型、String类、一些封装了基础数据类型的专门的类:Character、Byte、Short、Integer一起工作。
下面代码,声明一个int型变量month,其值表示月份;然后根据swich语句,打印月份。
public class SwitchDemo{
public static void main(String[] args){
int month = 8;
String monthStr;
switch(month){
case 1:monthStr = "January";
break;
case 2:monthStr = "February";
break;
case 3:monthStr = "March";
break;
case 4:monthStr = "April";
break;
case 5:monthStr = "May";
break;
case 6:monthStr = "June";
break;
case 7:monthStr = "July";
break;
case 8:monthStr = "August";
break;
case 9:monthStr = "September";
break;
case 10:monthStr = "October";
break;
case 11:monthStr = "November";
break;
case 12:monthStr = "December";
break;
default:monthStr = "Invalid month";
break;
}
System.out.println(monthStr);
}
}
输出是August。
switch语句体被称为switch块。switch块中可以有多个case标记和一个default标记的语句。switch语句计算表达式,执行跟在对应case标记后的所有语句。
你也可以使用if-then-else完成上面代码。
int month = 8;
if(month == 1){
System.out.println("January");
}else if(month == 2){
System.out.println("February");
}...
根据代码可读性和要测试的语句来决定使用switch语句还是if-then-else语句。if-then-else语句可以测试值的范围或条件,而switch语句只能根据一个整数、一个枚举值或一个String对象测试表达式。
另外一个有趣的地方是break语句。每一个break语句会终止一个switch块。控制流就继续执行跟在switch块后的第一条语句。break语句是必须的,如果没有它们,switch块中的语句会整个执行下去:匹配case标记后面的所有语句都会顺序执行,不管后面case的值是否匹配,直到碰到break语句。下面代码展示switch块从上而下整个执行,计算month对应月份和一年中其后的所有月份。
class SwitchFallThroughDemo{
public static void main(String[] args){
java.util.ArrayList<String> futureMonths = new java.util.ArrayList<String>();
int month = 8;
switch(month){
case 1:futureMonths.add("January");
case 2:futureMonths.add("February");
case 3:futureMonths.add("March");
case 4:futureMonths.add("April");
case 5:futureMonths.add("May");
case 6:futureMonths.add("June");
case 7:futureMonths.add("July");
case 8:futureMonths.add("August");
case 9:futureMonths.add("September");
case 10:futureMonths.add("October");
case 11:futureMonths.add("November");
case 12:futureMonths.add("December");
break;
default:break;
}
if(futureMonths.isEmpty()){
System.out.println("Invalid month number");
}else{
for(String month : futureMonths){
System.out.print(month+" ");
}
}
}
}
输出:August September October November December
技术上来说,最后一个break语句并不需要,因为流程已经流出switch语句。推荐使用break这样易于修改代码、减少错误可能性。default代码段处理所有没被case代码段处理的值。
下面例子展示一条语句有多个case标签。这个例子计算某月的天数。
class SwitchDemo2{
public static void main(String[] args){
int month = 2;
int year = 2000;
int numDays = 0;
switch(month){
case 1:caes 3:case 5:case 7: case 8:case 10:case 12:
numDays = 31;
break;
case 4:case 6:case 9:case 11:
numDays = 30;
break;
case 2:
if (((year % 4 == 0) && !(year % 100 == 0)) || (year % 400 == 0))
numDays = 29;
else
numDays = 28;
break;
default:
System.out.println("invalid month");
break
}
System.out.println("Number of Days = " + numDays);
}
}
输出:Number of Days = 29
switch语句中使用字符串
java7及其以后,你可以在switch语句表达式中使用String对象。下面例子,通过字符串展示月数。
public class StringSwitchDemo{
public static int getMonthNumber(String month){
int num = 0;
if(month == null)
return num;
switch(month.toLowCase()){
case "january":
num = 1;
break;
case "february":
num = 2;
break;
case "march":
num = 3;
break;
case "april":
num = 4;
break;
case "may":
num = 5;
break;
case "june":
num = 6;
break;
case "july":
num = 7;
break;
case "august":
num = 8;
break;
case "september":
num = 9;
break;
case "october":
num = 10;
break;
case "november":
num = 11;
break;
case "december":
num = 12;
break;
default:
num = 0;
break;
}
return num;
}
public static void main(String[] args){
String month = "august";
int num = StringSwitchDemo.getMonthNumber(month);
if(num == 0){
Sysem.out.println("invalid month");
}else{
System.out.println(num);
}
}
}
输出:8
switch表达式中的字符串与每个case标签表达式的比较就好像使用String.equals方法。为了忽略大小写,month参数转成小写(使用toLowCase方法),所有case标签的字符串都是小写。
注意,本例中检查switch表达式是否为null。确保switch表达式不为null,防止空指针异常。
while和do-while语句
while语句会一直执行块中的语句当条件为真。如下:
while(expression){
statement(s)
}
while语句计算表达式的值,表达式必须返回一个布尔值。如果表达式值为true,执行while块中的语句。while语句一直测试表达式和执行while块中的语句直到表达式的值为false。下面代码使用while语句打印1到10。
class WhileDemo{
public static void main(Sring[] args){
int count = 1;
while(count < 11){
System.out.println(count);
count++;
}
}
}
你可以使用while语句实现一个无限循环:
while(true){
}
java同时提供了do-while语句,如下:
do{
statement(s);
}while(expression);
while语句和do-while语句的区别在于do-while在循环的底部计算它的表达式,而while在顶部计算表达式。因此,do-while语句至少将其块执行一次。如下代码:
class DoWhileDemo{
public static void main(String[] args){
int count = 1;
do{
System.out.println(count);
count++;
}while(count<11);
}
}
for语句
for语句提供了一个简洁的方法遍历一个范围之中的值。程序中一般用它来循环,因为在for语句中,它不停的重复直到满足某个条件。通常for语句如下:
for(initialization;termination;increment){
statement(s);
}
使用这个版本的for语句时注意:
初始化表达式初始化这个循环,在循环开始时,执行一次;
当终止表达式计算得到false,循环终止;
循环的每次遍历之后,增加表达式都被执行,这里特别适用于增加或减少一个值;
下面程序使用通用的for语句来打印1到10:
class ForDemo{
public static void main(String[] args){
for(int i = 0; i < 11; i++){
System.out.print(i+" ");
}
}
}
输出为:1 2 3 4 5 6 7 8 9 10
注意在初始化表达式中如何声明一个变量。这个变量的作用域从它的声明延续到块的结束,由for语句管理,所以变量可以被终止表达式和增加表达式使用。如果控制for语句的变量并不需要在循环外部使用,那么这个变量最好在初始化表达式中声明。变量名i、j、k通常用于for循环;在初始化表达式中声明它们,可以限制它们的生命周期和减少错误。
for语句中的三个表达式都是可选的,如下就定义了一个无限循环语句:
for(;;;){
}
for语句还有其他的形式,针对集合和数组的遍历。这些形式当作for语句的增强版,可以让你的循环更加紧凑和易读。如下,考虑下面这个数组,拥有数字1到10:
int[] numbers = {1,2,3,4,5,6,7,8,9,10};
下面代码,使用增强版for语句遍历这个数组:
class EnhancedForDemo{
public static void main(String[] args){
int[] numbers = {1,2,3,4,5,6,7,8,9,10};
for(int item : numbers){
System.out.print(item+" ");
}
}
}
输出:1 2 3 4 5 6 7 8 9 10
我们推荐尽量使用增强版的for语句。
分支语句
break语句有两种形式:有标记和无标记的。你在switch语句中已经见过无标记的。你也可以使用无标记的break来终止一个for、while、do-while循环,如下代码:
class BreakDemo{
public static void main(String[] args){
int[] arrayOfInts = {32,87,3,589,
12,1076,2000,
8,622,127};
int searchfor = 12;
int i;
boolean foundIt = false;
for(i = 0; i < arrayOfInts.length; i++){
if(arrayOfInts[i] == searchfor){
foundIt = true;
break;
}
}
if(foundId){
System.out.println("Found " + searchfor + " at index " + i);
}else{
System.out.println(searchfor + " not in the array");
}
}
}
输出:Found 12 at index 4
程序在数组中寻找数字12。break语句,在数字找到时终止for循环,控制流跳到for循环后面的语句。
一个无标记的break语句终止最内层的switch、for、while、do-while语句,而一个有标记的break语句可以终止外层的循环语句。下面程序和上面程序类似,但是使用了嵌套的for循环在一个二维数组中找一个值。当值找到后,有标记的break终止外层的循环(标记"search")。
class BreakWithLabelDemo{
public static void main(String[] args){
int[][] arrayOfInts = {{32,87,3,589},{12,1076,2000,8},{622,127,77,955}};
int searchfor = 12;
int i;
int j = 0;
boolean foundIt = false;
search:
for(i = 0; i < arrayOfInts.length; i++){
for(j = 0; j < arrayOfInts[i].length; j++){
if(arrayOfInts[i][j] == searchfor){
foundIt = true;
break search;
}
}
}
if(fountId){
System.out.println("Found " + searchfor + " at index "+ i + " , " + j);
}else{
System.out.println(searchfor + " not in the array");
}
}
}
输出:Found 12 at index 1, 0
break语句终止了标记语句;它不会把控制流交回给标记语句。控制流跳到标记语句的后面一条语句。
在for、while、do-while循环中使用continue语句跳过当前的遍历。无标签的形式跳到最内层循环的结尾,并计算控制循环的布尔表达式。下面程序对一个字符串,计算出现的字母p。当果当前字母不是p,continue语句跳过循环的剩余部分,并处理下一个字母。如果是p,计数加1。
class ContinueDemo{
public static void main(String[] args){
String searchMe = "peter piper picked a " + "peck of pickled peppers";
int max = searchMe.length();
int numPs = 0;
for(int i = 0; i < max; i++){
if(searchMe.charAt(i) != ‘p‘)
continue;
numPs++;
}
System.out.println("found " + numPs + " p in the string");
}
}
输出:found 9 p in the string
为了使效果更加清晰,试试去掉continue,重新执行。结果变成了35个p。
一个有标记的continue语句跳过当前的遍历,从标记的外层循环中。下面的例子使用嵌套循环在一个字符串中寻找子字符串。两个嵌套循环是需要的:一个循环遍历被寻找的字符串,一个遍历子字符串。下面代码用有标记的continue跳过外层循环的遍历。
class ContinueWithLabelDemo{
public static void main(String[] args){
String searchMe = "look for a substring in me";
String substring = "sub";
boolean foundIt = false;
int max = searchMe.length() - substring.length();
test:
for(int i = 0; i < max; i++){
int n = substring.length();
int j = 0;
int k = i;
while(n-- != 0){
if(searcchMe.charAt(k++) != substring.charAt(j++)){
continue test;
}
}
foundIt = true;
break test;
}
System.out.println(foundIt ? "found it" : "not found it");
}
}
输出:found it
最后一条分支语句是return语句。return语句从当前方法中退出,控制流返回到该方法调用的位置。return语句有两种形式:一种返回一个值,一种不返回值。返回值(或者是一个表达式计算出一个值)只需要把值跟在return的后面。
return ++count;
返回的值的数据类型必须匹配方法声明的返回值的类型。当方法声明void,使用不返回值的return。
return
后面会讲到方法。
控制流语句总结
if-then语句是所有控制流语句中最常用的。它告诉你的程序去执行某段代码当你的条件计算为true时。if-then-else语句提供了第二条执行路径当if分句计算为false。不像if-then和if-then-else,switch语句允许任意数量的执行路径。当某个条件为真时,while和do-while语句一直执行一块语句。while和do-while的区别是do-while在循环的底部计算它的表达式,而不是顶部。因此,do-while中的块语句至少执行一遍。for语句提供简洁的方法遍历一个范围内的值。它有两个形式,其中一个是针对集合和数组的。
(翻译)《二》语言基础(4)--控制流语句