您的位置:首页 > 编程语言 > Java开发

读thinking in java笔记(三):控制执行流程

2016-09-02 22:59 393 查看
就像有知觉的生物一样,程序必须在执行过程中控制它的世界,并做出选择。在Java中你要执行控制语句来做出选择。

java中使用了C的所有流程控制语句。在Java中涉及的关键字包括if-else、while、do-while、for、return、break以及选择语句switch。然而,Java并不支持goto语句,(该语句引起很多反对意见,但它仍是解决某些特殊问题的最便利的方法)。在Java中,仍然可以进行类似goto那样的跳转,但比起典型的goto,有了很多限制。

1. true和false

所有条件语句都利用条件表达式的真或假来决定执行路径。在前面介绍的所有关系操作符,都可拿来构造条件语句。注意Java不允许我们将一个数字作为布尔值来使用,虽然这在C和C++里是允许的(在这些语言里,“真”是非零,而“假”是零)。如果想在布尔测试中使用一个非布尔值,比如在if(a)中,那么首先必须用一个条件表达式将其转换成布尔值,例如if(a!=0)。

2. if-esle

if-else语句是控制程序流程最基本的形式。其中的else是可选的,所以可按下面两种形式来使用if:

if(Boolean-expression)
statement
或
if(Boolean-expression)
statement
else
statement


布尔表达式必须产生一个布尔结果,statement指用分号结尾的简单语句或复合语句(封闭在花括号内的一组简单语句)。在本书任何地方,只要提及“语句”这个词,就指的是简单语句或复合语句。

例子:告诉您,您猜的数是大于、小于还是等于目标数。
public class IfElse {

public static void main(String[] args) {
testVal(6, 2);
testVal(4, 8);
testVal(5, 5);
}

public static void testVal(int testVal, int target) {
if (testVal > target) {
System.out.println("您输入的值大于目标值,请重新输入!");
} else if (testVal < target) {
System.out.println("您输入的值小于目标值,请重新输入!");
} else {
System.out.println("恭喜您猜对了!");
}
}
}


2. 迭代

while、do-while和for用来控制循环,有时将它们划分为迭代语句(iteration statement)。语句会重复执行,直到起控制作用的布尔表达式(Boolean-expression)得到“假”的结果为止。

2.1 while

while格式如下:

while(Boolean-expression)
statement


在循环刚开始时会计算一次布尔表达式的值;而在语句的下一次迭代开始前会再计算一次。

例子:产生随机数,直到符合特定的条件为止。
public class WhileTest {

public static void main(String[] args) {
while (condition()) {
System.out.println("inside while");
}
System.out.println("outside while");
}

public static boolean condition(){
boolean result = Math.random() < 0.99;
System.out.println(result + ",");
return result;
}
}


condition()方法用到了Math库里的static(静态)方法random(),该方法的作用是产生0和1之间(包含0,不含1)的一个double值(这个double值小数点后有16位)。result的值是通过比较操作符<而得到的,这个操作符将产生double类型的结果。while条件表达式的意思是说:“只要condition()返回true,就重复执行循环体重的语句”。

2.2 do-while

do-while格式如下:

do
statement
while(boolean-expression);


while和do-while唯一区别就是do-while中的语句至少会执行一次,即便表达式第一次就被计算为false。而在while循环结构中,如果条件第一次就为false,那么其中的语句根本不会执行。在实际应用中,while比do-while更常用一些。其实之所以do-while至少会执行一次是因为它是先执行一次再判断的布尔表达式。

2.3 for

for循环可能是最经常使用的迭代形式,这种在第一次迭代之前要进行初始化。随后它会进行条件测试,而且在每一次迭代结束时,进行某种形式的“步进”。for循环的格式如下:

for(initialization; boolean-expression; step)
statement


初始化(initialization)表达式、布尔表达式(Boolean-expression),步进(step);每次迭代前会测试布尔表达式。若获得的结果为false,就会执行for语句后面的代码行,每次循环结束后,会执行一次步进。

例子:
public class ListCharacters {

public static void main(String[] args) {
for (char c = 0; c < 100; c++) {
if (Character.isLowerCase(c)) {
System.out.println("value:" + (int)c + "  characters: " + c);
}
}
}
}
//备注:Character.isLowerCase();判断是否为一个小写字母;
//if(布尔表达式)


注意:变量c是在程序用到它的地方被定义的,也就是在for循环的控制表达式里,而不是在main()开始的地方定义的。c的作用域就是for控制表达式的范围内。

这个程序也使用了java.lang.Character包装器类,这个类不但能把char基本类型的值包装进对象,还提供了一些别的有用的方法。这里用到了static isLowerCase();来检查问题中的字符是否为小写字母。

练习1:打印1到100的值。
public class PrintVal {
public static void main(String[] args) {
for (int i = 0; i <= 100; i++) {
System.out.println(i);
}
}
}


2.4 逗号操作符

本章前面已经提到了逗号操作符(注意不是逗号分隔符,逗号用作分隔符时用来分隔函数的不同参数),Java里唯一用到逗号操作符的地方就是for循环的控制表达式。在控制表达式的初始化和步进控制部分,可以使用一系列有逗号分隔的语句;而且那些语句均会独立执行。通过使用逗号操作符,可以在for语句内定义多个变量,但是它们必须具有相同的类型。控制表达式(初始化表达+布尔表达式+步进)

例子:
public class CommaOperator {
public static void main(String[] args) {
for(int i = 1, j = i + 10; i < 5; i++, j = i * 2) {
System.out.println("i = " + i + " j = " + j);
}
}
} /* Output:
i = 1 j = 11
i = 2 j = 4
i = 3 j = 6
i = 4 j = 8
*/


for语句中的int定义涵盖了i和j,在初始化部分实际上可以拥有任意数量的具有相同类型的变量定义。在一个控制表达式中,定义多个变量的这种能力只限于for循环使用,在其他任何选择或迭代语句中都不能用这种方式。可以看到,无论在初始化部分还是在步进部分,语句都是顺序执行的。此外,初始化部分可以有任意数量的同一类型的定义。

3. foreach语法

JavaSE5引入了一种新的更加简洁的for语法用于数组和容器,即foreach语法,表示不必创建int变量去对由访问项构成的序列进行计数,foreach将自动产生每一项。

例子:假设有一个float数组,我们要选取该数组中的每一个元素
public class ForeachFloat {

public static void main(String[] args) {
Random rand = new Random(12);
float[] farr = new float[10];
for (int i = 0; i < farr.length; i++) {
farr[i] = rand.nextInt(100);
}
for (float f : farr) {
System.out.println(f);
}
}
}


这个数组是用旧式的for循环组装的,因为在组装时必须按索引访问它。上面我们看到了foreach的语法:for (float f : farr) 这条语句定义了一个float类型的变量f,继而将每一个farr的元素赋值给x。任何一个返回数值的方法都可以使用foreach,例如:String类有一个方法toCharArray(),它返回一个char数组,我们可以很容易的迭代在字符串中的字符。

public class ForeachString {

public static void main(String[] args) {
for (char ch : "this is String".toCharArray()) {
System.out.print(ch + " ");
}
}
}
//备注:println();换行    print();不换行


4. return

在Java中有多个关键词表示无条件分支,它们只是表示这个分支无需任何测试即可发生。这些关键词包括return、break、continue。

return关键词有两方面的用途:1.指定一个方法返回什么值(假设返回的不是void);2.它会导致当前方法的退出,并返回那个值。

public class IfElse2 {

public static int testVal(int testVal,int target){
if(testVal > target){
return -1;
}else if(testVal < target){
return +1;
}else{
return 0;
}
}
public static void main(String[] args) {
System.out.println(testVal(6, 2));
System.out.println(testVal(2, 4));
System.out.println(testVal(3, 3));
}
}


如果在返回void的方法中没有return语句,那么在该方法的结尾处会有一个隐式的return,因此在方法中并非总是要有一个return语句。但是,如果一个方法声明它将返回void之外的其他东西,那么必须确保每一条代码路径都将返回一个值。

5. break和continue

在任何迭代语句的主体部分,都可用break和continue控制循环的流程。其中,break用于强行退出循环,不执行循环中剩余的语句。而continue则停止执行当前的迭代,然后退回循环起始处,开始下一次迭代。

例子:
public class BreakAndContinue {
public static void main(String[] args) {
//        for (int i = 0; i < 100; i++) {
//            if (i == 74) break;
//            if(i%9 != 0) continue;
//            System.out.print(i + " ");
//        }
int i = 0;
while (true) {
i++;
int j = i * 27;
if(j == 1269) break;
if(j % 10 != 0) continue;
System.out.print(i + " ");
}
}
for的结果
/**
* 0 9 18 27 36 45 54 63 72
*/

//while 的结果
/**
* 10 20 30 40
*/
}


在这个for循环中,i的值永远不会达到100;因为一旦i达到74,break语句就会中断循环。通常,只有在不知道中断条件何时满足时,才需要这样使用break。只要i不能被9整除,continue语句就会使执行过程返回到循环的最开头(这使i值递增)。如果能够整除,则将值显示出来。

最后,可以看到一个“无穷while循环”的情况。然而,循环内部有一个break语句,可中止循环。除此之外,大家还会看到continue语句执行序列移回道循环的开头,而没有去完成continue语句之后的所有内容。(只有在i值能被10整除时才打印出值),输出结果之所以显示0是因为0%9等于0。

无穷循环的第二种形式是for(; ;)。编译器将while(true)与for(; ;)看作是同一回事。所以具体使用选用哪个取决于自己的编程习惯。

6. switch

switch有时也被划归为一种选择语句。根据整数表达式的值,switch语句可以从一系列代码中选出一段去执行。它的格式为:

switch(integral-selector){
case integral-value1 : statement; break;
case integral-value2 : statement; break;
case integral-value3 : statement; break;
case integral-value4 : statement; break;
case integral-value5 : statement; break;
//...
default: statement;
}


其中,integral-selector(整数选择因子)是一个能够产生整数值的表达式,switch能将这个表达式的结果与每个integral-value(整数值)相比较。若发现相符,就执行对应的语句(单一语句或多条语句,其中并不需要括号)。若没有发现相符的,就执行default(默认)语句。

在上面的定义中,大家会注意到每个case均以一个break结尾,这样可使执行流程跳转到switch主体的末尾。这是构建switch语句的一种传统形式,但break是可选的。若省略break,会继续执行后面的case语句,直到遇到一个break为止。尽管通常不想出现这种情况,但对有经验的程序员而言,也许能善加利用这种情况。注意最后的default语句没有break,因为执行流程已到了break的跳转目的地。当然,为了考虑到编程风格的原因,完全可以在default语句的末尾放置一个break,尽管它并没有任何实际的用处。

switch语句是实现多路选择(也就是说从一系列执行路径中挑选一个)的一种干净利落的方法。但它要求使用一个选择因子,并且必须是int或char那样的整数值。例如:假若将一个字符串或者浮点数作为选择因子使用,那么它们在switch语句里是不会工作的。对于非整数类型,则必须使用一系列if语句。

例子:可随机生成字母,并判断它们是元音还是辅音字母。
public class VowelsAndConsonants {
public static void main(String[] args) {
Random rand = new Random(47);
for(int i = 0; i < 100; i++) {
int c = rand.nextInt(26) + 'a';
printnb((char)c + ", " + c + ": ");
switch(c) {
case 'a':
case 'e':
case 'i':
case 'o':
case 'u': print("vowel");
break;
case 'y':
case 'w': print("Sometimes a vowel");
break;
default:  print("consonant");
}
}
}
} /* Output:
y, 121: Sometimes a vowel
n, 110: consonant
z, 122: consonant
b, 98: consonant
r, 114: consonant
n, 110: consonant
y, 121: Sometimes a vowel
g, 103: consonant
c, 99: consonant
f, 102: consonant
o, 111: vowel
w, 119: Sometimes a vowel
z, 122: consonant
...
*/


由于Rondom.nextInt(26)会产生0~26之间的一个值,所以在其上加上一个偏移量‘a’,即可产生小写字母。在case语句中,使用单引号引起的字符也会产生用于比较的整数值。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: