java编程思想_控制执行流程_0401
第4章 控制执行流程
程序必须在执行过程中控制它的世界,并做出选择。在Java中使用执行控制语句来做出选择。
4.1true和false
条件语句利用条件表达式的真或假来决定执行路径。
例如条件表达式a==b,用条件操作符“==”来判断a值是否等于b值。该表达式返回true或false。
Java不允许将一个数字作为布尔值使用,
4.2if-else
if-else语句,控制程序流程。
else是可选的,可按下述两种形式来使用if:
if(Boolean-expression)
statement
或
if(Boolean-expression)
statement
else
statement
布尔表达式必须产生一个布尔结果。
statement指用分号结尾的简单语句,或复合语句(封闭在花括号内的一组简单语句)。
例:test(),您猜的是大于,小于还是等于目标数。
1 //:control/IfElse.java 2 package control; 3 import static util.Print.*; 4 5 public class IfElse { 6 static int result=0; 7 static void test(int testval,int target) { 8 if(testval>target) 9 result=+1; 10 else if(testval<target) 11 result=-1; 12 else 13 result=0;//Match 14 } 15 16 public static void main(String[] args) { 17 test(10,5); 18 print(result); 19 test(5,10); 20 print(result); 21 test(5,5); 22 print(result); 23 } 24 25 }
Output:
else if不是新的关键字,仅仅是一个else后面紧跟另一个新的if语句。
Java是格式自由的语言,但是习惯上将流程控制语句的主体部分缩进排列,使读者能方便地确定起始与终止。
4.3迭代
while、do-while和for用来控制循环,有时将它们划分为迭代语句(iteration statement)。
语句会重复执行,直到起控制作用的布尔表达式得到“假”的结果为止。
while循环的格式如下:
while(Boolean-expression)
statement
在循环刚开始时,会计算一次布尔表达式的值;
而在语句的下一次迭代开始前会再计算一次。
例:下面这个例子可产生随机数,直到符合特定的条件为止:
1 //:control/WhileTest.java 2 //Demonstrates the while loop. 3 package control; 4 5 public class WhileTest { 6 static boolean condition() { 7 boolean result=Math.random()<0.99; 8 System.out.print(result+","); 9 return result; 10 } 11 12 public static void main(String[] args) { 13 while(condition()) 14 System.out.println("Inside 'while'"); 15 System.out.println("Exited 'while'"); 16 17 } 18 19 }
Output:
Math库里的static方法random(),产生0和1之间(包括0,但不包括1)的一个double值。
result的值是通过比较操作符<而得到它,这个操作符将产生boolean类型的结果。
while条件语句,只要condition()返回true,就重复执行循环体中的语句。
4.3.1do-while
do-while的格式如下:
do
statement
while(Boolean-expression);
do-while中的语句至少会执行一次。
4.3.2for
for循环可能是最经常使用的迭代形式,这种在第一次迭代之前要进行初始化。
随后,它会进行条件测试,而且在每一次迭代结束时,进行某种形式的“步进”。
for循环的格式如下:
for(initialization;Boolean-expression;step)
statement
初始化表达式,布尔表达式,或者步进运算都可以为空。
每次迭代前会测试布尔表达式。若获得的结果是true,就会执行for语句后面的代码行。每次循环结束,会执行一次步进。
例:for循环用于执行“计数”任务:
1 //:control/ListCharacters.java 2 //Demonstrates "for" loop by listing 3 //all the lowercase ASCII letters. 4 package control; 5 6 public class ListCharacters { 7 8 public static void main(String[] args) { 9 for(char c=0;c<128;c++) 10 if(Character.isLowerCase(c)) 11 System.out.println("value:"+(int)c+"character:"+c); 12 13 } 14 15 }
Output:
变量c是在for循环的控制表达式里被定义的。c的作用域就是for控制的表达式的范围内。
这里用到了java.lang.Character包装器类,这个类不但能把char基本类型的值包装进对象,还提供了一些别的有用的方法。这里用到了static isLowerCase()方法来检查问题中的字符是否为小写字母。
C语言,要求所有变量都在一个块的开头定义,以便编译器在创建这个块的时候,可以为那些变量分配空间。
在Java和C++中,则可在整个块的范围内分散变量申明,在真正需要的地方才加以定义。这样便可形成更自然的编码风格,也更易理解。
练习1:
(1)写一个程序,打印从1到100的值。
1 package control; 2 3 public class CoTest1 { 4 5 public static void main(String[] args) { 6 for(int i=0;i<100;i++) 7 System.out.println((i+1)); 8 9 } 10 11 }
Output:
练习2:
(2)写一个程序,产生25个int类型的随机数。对于每一个随机值,使用if-else语句来将其分类为大于、小于,或等于紧随它而随机生成的值。
1 package control; 2 3 public class CoTest2 { 4 5 public static void main(String[] args) { 6 int a[]=new int[25]; 7 for(int i=0;i<25;i++) { 8 a[i]=(int)(Math.random()*100); 9 10 11 } 12 for(int j=0;j<24;j++) { 13 if(a[j]>a[j+1]) 14 System.out.println("第"+(j+1)+"个数"+a[j]+">第"+(j+2)+"个数"+a[j+1]); 15 else if(a[j]<a[j+1]) 16 System.out.println("第"+(j+1)+"个数"+a[j]+"<第"+(j+2)+"个数"+a[j+1]); 17 else 18 System.out.println("第"+(j+1)+"个数"+a[j]+"=第"+(j+2)+"个数"+a[j+1]); 19 } 20 21 22 23 } 24 25 }
Output:
练习3:
修改练习2,把代码用一个while无限循环包括起来。然后运行它直至用键盘中断其运行(通常是通过按Ctrl-C)。
1 package control; 2 3 public class CoTest3 { 4 5 public static void main(String[] args) { 6 int a[]=new int[25]; 7 while(true) { 8 for(int i=0;i<25;i++) { 9 a[i]=(int)(Math.random()*100); 10 11 12 } 13 for(int j=0;j<24;j++) { 14 if(a[j]>a[j+1]) 15 System.out.println("第"+(j+1)+"个数"+a[j]+">第"+(j+2)+"个数"+a[j+1]); 16 else if(a[j]<a[j+1]) 17 System.out.println("第"+(j+1)+"个数"+a[j]+"<第"+(j+2)+"个数"+a[j+1]); 18 else 19 System.out.println("第"+(j+1)+"个数"+a[j]+"=第"+(j+2)+"个数"+a[j+1]); 20 } 21 } 22 23 } 24 25 }
Output:
练习4:
(3)写一个程序,使用两个嵌套的for循环和取余操作符(%)来探测和打印素数(只能被其自身和1整除,而不能被其他数字整除的整数)。
练习5:
(4)重复第3章中的练习10,不要用Integer.toBinaryString()方法,而是用三元操作符和按位操作符来显示二进制的1和0。
4.3.3逗号操作符
逗号分隔符,用来分隔函数的不同参数。
逗号操作符,Java里唯一用到逗号操作符的地方就是for循环的控制表达式。
在控制表达式的初始化和步进控制部分,可以使用一系列由逗号分隔的语句;而且那些语句均会独立执行。
通过使用逗号操作符,可以在for语句内定义多个变量,但是它们必须具有相同的类型。
1 //:control/CommaOperator.java 2 package control; 3 4 public class CommaOperator { 5 6 public static void main(String[] args) { 7 // TODO Auto-generated method stub 8 for(int i=1,j=i+10;i<5;i++,j=i*2) { 9 System.out.println("i="+i+"j="+j); 10 } 11 12 } 13 14 }
Output:
for语句中的int定义涵盖了i和j,在初始化部分实际上可以拥有任意数量的具有相同类型的变量定义。
无论在初始化还是在步进部分,语句都是顺序执行的。
初始化部分可以有任意数量的同一类型的定义。
4.4Foreach语法
Java SE5引入,一种新的更加简洁的for语法用于数组和容器。
即foreach语法,不必创建int变量去对由访问项构成的序列进行计数,foreach将自动产生每一项。
例:假设有一个float数组,我们要选取该数组中的每一个元素:
1 //:control/ForEachFloat.java 2 package control; 3 import java.util.*; 4 5 public class ForEachFloat { 6 7 public static void main(String[] args) { 8 Random rand=new Random(47); 9 float f[]=new float[10]; 10 for(int i=0;i<10;i++) 11 f[i]=rand.nextFloat(); 12 for(float x:f) 13 System.out.println(x); 14 15 } 16 17 }
Output:
这个数组是用旧式的for循环组装的,因为在组装时必须按索引访问它。
foreach语法:
for(float x:f){
这条语句定义了一个float类型的变量x,继而将每一个f的元素赋值给x。
任何返回一个数组的方法都可以使用foreach。
例如,String类有一个方法toCharArray(),它返回一个char数组,因此可以像下面这样迭代在字符串里面的所有字符:
1 //:control/ForEachString.java 2 package control; 3 4 public class ForEachString { 5 6 public static void main(String[] args) { 7 for(char c:"An African Swallow".toCharArray()) 8 System.out.print(c+" "); 9 10 } 11 12 }
Output:
foreach还可用于任何Iterable对象。
许多for语句都会在一个整型值序列中步进,就像下面这样:
for(int i=0;i<100;i++)
对于这些语句,foreach语法将不起作用,除非先创建一个int数组。
我在net.mindview.util.Range包中创建了一个名为range()的方法,它可以自动地生成恰当的数组。
我的目的是将range()用做static导入:
1 //:control/ForEachInt.java 2 package control; 3 import static util.Range.*; 4 import static util.Print.*; 5 6 public class ForEachInt { 7 8 public static void main(String[] args) { 9 for(int i:range(10))//0..9 10 printnb(i+" "); 11 print(); 12 for(int i:range(5,10))//5..9 13 printnb(i+" "); 14 print(); 15 for(int i:range(5,20,3))//5..20 step3 16 printnb(i+" "); 17 print(); 18 19 } 20 21 }
range()方法已经被重载,重载表示相同的方法名可以具有不同的参数列表。
range()的第一种重载形式是从0开始产生值,直至范围的上限,但不包括该上限。
第二种形式从第一个值开始产生值,直至比第二个值小1的值为止。
第三种形式有一个步进值,因此它每次的增量为该值。
range()使得foreach语法可以适用于更多的场合,并且这样做似乎可以增加可读性,但是它的效率会稍许降低,因此如果您在做性能调优,也许应该使用仿真器来做评价,它是一种可以度量代码性能的工具。
除了print()之外,我们还使用了printnb()。printnb()方法不会换行,因此可以使用它将一行拆分成多个片段输出。
foreach语法不仅在录入代码时可以节省时间,它阅读起来也要容易得多。
它说明您正在努力做什么(例如获取数组中的每一个元素),而不是给出你正在如何做的细节(例如正在创建索引,因此可以使用它来选取数组中的每一个元素)。在本书中,我们只要有可能就会使用foreach语法。
4.5return
Java中的多个关键词表示无条件分支,它们只是表示这个分支无需任何测试即可发生。这些关键词包括return,break,continue和一种与其他语言中的goto类似的跳转到标号语句的方式。
return关键词有两方面的用途:
一方面指定一个方法返回什么值(假设它没有void返回值),另一方面它会导致当前的方法退出,并返回那个值。
1 //:control/IfElse2.java 2 package control; 3 import static util.Print.*; 4 5 public class IfElse2 { 6 static int test(int testval,int target) { 7 if(testval>target) 8 return +1; 9 else if(testval<target) 10 return -1; 11 else 12 return 0;//Match 13 } 14 15 public static void main(String[] args) { 16 print(test(10,5)); 17 print(test(5,10)); 18 print(test(5,5)); 19 20 } 21 22 }
Output:
不必加上else,因为方法在执行了return后不再继续执行。
如果在返回void的方法中没有return语句,那么在该方法的结尾处会有一个隐式的return,因此在方法中并非总是必须要有一个return语句。但是,如果一个方法声明它将返回void之外的其他东西,那么必须确保每一条代码路径都将返回一个值。
练习6:
(2)修改前两个程序中的两个test()方法,让它们接受两个额外的参数begin和end,这样在测试testval时将判断它是否在begin和end之间(包括begin和end)的范围内。
1 package control; 2 import static util.Print.*; 3 4 public class CoTest61 { 5 static int result=0; 6 static char c; 7 static void test(int testval,int target,int begin,int end) { 8 if(testval>target) 9 result=+1; 10 else if(testval<target) 11 result=-1; 12 else 13 result=0;//Match 14 if(testval>=begin&&testval<=end) 15 c='Y'; 16 else 17 c='N'; 18 } 19 20 public static void main(String[] args) { 21 test(10,5,9,13); 22 print(result); 23 print(c); 24 test(5,10,9,13); 25 print(result); 26 print(c); 27 test(5,5,9,13); 28 print(result); 29 print(c); 30 } 31 32 }
Output:
1 package control; 2 import static util.Print.*; 3 4 public class CoTest62 { 5 static char test(int testval,int begin,int end) { 6 if(testval>=begin&&testval<=end) 7 return 'Y'; 8 9 else 10 return 'N'; 11 } 12 13 public static void main(String[] args) { 14 print(test(10,9,13)); 15 print(test(5,9,13)); 16 print(test(5,9,13)); 17 18 } 19 20 }
Output:
4.6 break和continue
在任何迭代语句的主体部分,都可用break和continue控制循环的流程。
break用于强行退出循环,不执行循环中剩余的语句。
continue停止执行当前的迭代,然后退回循环起始处,开始下一次迭代。
break和continue在for和while循环中的例子。
1 //:control/BreakAndContinue.java 2 //Demonstrates break and continue keywords. 3 package control; 4 import static util.Range.*; 5 6 public class BreakAndContinue { 7 8 public static void main(String[] args) { 9 for(int i=0;i<100;i++) { 10 if(i==74)break;//Out of for loop 11 if(i%9!=0) continue;//Next iteration 12 System.out.print(i+" "); 13 } 14 System.out.println(); 15 //Using foreach: 16 for(int i:range(100)) { 17 if(i==74) break; //Out of for loop 18 if(i%9!=0)continue;//Next iteration 19 System.out.print(i+" "); 20 } 21 System.out.println(); 22 int i=0; 23 //An "infinite loop": 24 while(true) { 25 i++; 26 int j=i*27; 27 if(j==1269)break;//Out of loop 28 if(i%10!=0)continue;//Top of loop 29 System.out.print(i+" "); 30 } 31 32 } 33 34 }
1 //:control/BreakAndContinue.java 2 //Demonstrates break and continue keywords. 3 package control; 4 import static util.Range.*; 5 6 public class BreakAndContinue { 7 8 public static void main(String[] args) { 9 for(int i=0;i<100;i++) { 10 if(i==74)break;//Out of for loop 11 if(i%9!=0) continue;//Next iteration 12 System.out.print(i+" "); 13 } 14 System.out.println(); 15 //Using foreach: 16 for(int i:range(100)) { 17 if(i==74) break; //Out of for loop 18 if(i%9!=0)continue;//Next iteration 19 System.out.print(i+" "); 20 } 21 System.out.println(); 22 int i=0; 23 //An "infinite loop": 24 while(true) { 25 i++; 26 int j=i*27; 27 if(j==1269)break;//Out of loop 28 if(i%10!=0)continue;//Top of loop 29 System.out.print(i+" "); 30 } 31 32 } 33 34 }
在这个for循环中,i的值永远不会达到100;因为一旦i到达74,break语句就会中断循环。
通常,只有在不知道中断条件何时满足时,才需要这样使用break。只要i不能被9整除,continue语句就会使执行过程返回到循环的最开头(这使i值递增)。如果能够整除,则将值显示出来。
第二种for循环展示了foreach用法,它将产生相同的结果。
“无穷while循环”的情况,循环内部有一个break语句,可终止循环。除此之外,大家还会看到continue语句执行序列移回到循环的开头,而没有去完成continue语句之后的所有内容。(只有在i值能被10整除时才打印出值。)
无穷循环的第二种形式是for(;;).编译器将while(true)和for(;;)看作是同一回事。
练习7:
(1)修改本章练习1,通过使用break关键词,使得程序在打印到99时退出。然后尝试使用return来达到相同的目的。
1 package control; 2 3 public class CoTest7 { 4 5 public static void main(String[] args) { 6 for(int i=0;i<100;i++) { 7 if(i==99)break; 8 System.out.println((i+1)); 9 } 10 11 } 12 13 }
Output:
1 package control; 2 3 public class CoTest7 { 4 5 public static void main(String[] args) { 6 for(int i=0;i<100;i++) { 7 if(i==99)return; 8 System.out.println((i+1)); 9 } 10 11 } 12 13 }
Output: