logo资料库

疯狂Java讲义+疯狂+Java讲义.pdf

第1页 / 共36页
第2页 / 共36页
第3页 / 共36页
第4页 / 共36页
第5页 / 共36页
第6页 / 共36页
第7页 / 共36页
第8页 / 共36页
资料共36页,剩余部分请下载后查看
疯狂 讲义 不论哪一种编程语言,都会提供两种基本的流程控制结构:分支结构和循环结构。其中分支结构用 于实现根据条件来选择性地执行某段代码,循环结构则用于根据循环条件重复执行某段代码。Java 同样 提供了这两种流程控制结构的语法,Java 提供了 if 和 switch 两种分支语句,并提供了 while、do while 和 for 三种循环语句,除此之外,JDK1.5 还提供了一种新的循环:foreach 循环,能以更简单的方式来遍 历集合、数组的元素。除此之外,Java 还提供了 break 和 continue 来控制程序的循环结构。 数组也是大部分编程语言都支持的数据结构,Java 也不例外。Java 的数组类型是一种引用类型的 变量,Java 程序通过数组引用变量来操作数组,包括获得数组的长度,访问数组元素的值等。本章将 会详细介绍 Java 数组的相关知识,包括如何定义、初始化数组等基础知识,并会深入介绍数组在内存 中的运行机制。 4.1 顺序结构 任何编程语言中最常见的程序结构就是顺序结构。顺序结构就是程序从上到下一行一行地执行, 中间没有任何判断和跳转。 如果 main 方法多行代码之间没有任何流程控制,则程序总是从上向下依次执行,排在前面的代码 先执行,排在后面的代码后执行。这意味着:如果没有流程控制,Java 方法里的语句是一个顺序执行 流,从上向下依次执行每条语句。 4.2 分支结构 Java 提供了两种常见的分支控制结构:if 语句和 switch 语句,其中 if 语句使用布尔表达式或布尔值 作为分支条件来进行分支控制;而 switch 语句则用于对多个整型值进行匹配,从而实现分支控制。 4.2.1 if 条件语句 if 语句使用布尔表达式或布尔值作为分支条件来进行分支控制,其中 if 语句有如下三种形式: 第一种形式: if ( logic expression ) { } statements... 第二种形式: if (logic expression) { } statements... else { } statements... 第三种形式: if (logic expression) { statements... } else if(logic expression) { statements... } 72
...//可以有零个或多个 else if 语句 else//最后的 else 语句也可以省略 { statement.. } 在上面 if 语言的三种形式中,放在 if 之后的括号里的只能是一个逻辑表达式,即这个表达式的返 回值只能是 true 或 false。第二种情形和第三种情形是相通的,如果第三种形式中 else if 块不出现,则 变成了第二种形式。 上面的条件语句中,if(logic expression)、else if(logic expression)以及 else 后花括号括起来多行代码 被称为代码块,一个代码块通常被当成一个整体来执行(除非运行过程中遇到 return、break、continue 等关键字,或者遇到了异常),因此这个代码块也被称为条件执行体。例如如下程序: 程序清单:codes/04/4-2/TestIf.java public class TestIf { public static void main(String[] args) { int age = 30; if (age > 20) //只有当 age > 20 时,下面花括号括起来的语句块才会执行 //花括号括起来的语句是一个整体,要么一起执行,要么一起不会执行 { System.out.println("年龄已经大于 20 岁了"); System.out.println("20 岁以上的人应该学会承担责任..."); } } } 因此,如果 if(logic expression)、else if(logic expression)和 else 后的语句块只有一行语句时,则可 以省略花括号,因为单行语句本身就是一个整体,无须花括号来把它们定义成一个整体。下面代码完 全可以正常执行(程序清单同上): //定义变量 a ,并为其赋值 int a = 5; if (a > 4) //如果 a>4,执行下面的执行体,只有一行代码作为代码块 System.out.println("a 大于 4"); else //否则,执行下面的执行体,只有一行代码作为代码块 System.out.println("a 不大于 4"); 通常,我们建议不要省略 if、else、else if 后执行块的花括号,即使条件执行体只有一行代码,因 为保留花括号会有更好的可读性,而且保留花括号会减少发生错误的可能,例如如下代码,则不可正 常执行: //定义变量 b ,并为其赋值 int b = 5; if (b > 4) //如果 b>4,执行下面的执行体,只有一行代码作为代码块 System.out.println("b 大于 4"); else //否则,执行下面的执行体 b--; //对于下面代码而言,它已经不再是条件执行体的一部分,因此总会执行 System.out.println("b 不大于 4"); 上面代码中以粗体字标识的代码行:System.out.println("b 不大于 4");,将总是会执行,因为这行 73
疯狂 代码并不属于 else 后的条件执行体,else 后的条件执行体就是 b--;这行代码。 讲义 if、else、else if 后条件执行体要么是一个花括号扩起来的语句块,则这个语句块整 体作为条件执行体;要么是以分号为结束符的一行语句,甚至可能是一个空语句(空语 句是一个分号)。 如果 if 块后有多条语句作为条件执行体,如果省略了这个条件执行体的花括号,则会引起编译错 误,看下面代码(程序清单同上): //定义变量 c ,并为其赋值 int c = 5; if (c > 4) //如果 c>4,执行下面的执行体,将只有 c--;一行代码为条件执行体 c--; //下面是一行普通代码,不属于条件执行体 System.out.println("c 大于 4"); //此处的 else 将没有 if 语句,因此编译出错 else //否则,执行下面的执行体,只有一行代码作为代码块 System.out.println("c 不大于 4"); 在上面代码中,因为 if 后的条件执行体省略了花括号,则系统只把 c--;一行代码作为条件执行体, 当 c-;语句结束后,if 语句也就结束了。后面的 System.out.println("c 大于 4");代码已经是一行普通代码 了,不再属于条件执行体,从而导致 else 语句没有 if 语句,从而引起编译错误。 对于 if 语句,还有一个很容易出现的逻辑错误,这个逻辑错误并不属于语法问题,但引起错误的 可能性更大。看下面程序: 程序清单:codes/04/4-2/TestIfError.java public class TestIfError { public static void main(String[] args) { int age = 45; if (age > 20) { } System.out.println("青年人"); else if (age > 40) { } System.out.println("中年人"); else if (age > 60) System.out.println("老年人"); { } } } 表面上看起来,上面的程序没有任何问题:人的年龄大于 20 岁时是青年人,年龄大于 40 岁是中 年人,年龄大于 60 岁是老年人。但运行上面程序,发现打印结果是:青年人,而实际上我们希望 45 岁应判断为中年人——这显然出现了一个问题。 对于任何的 if else 语句,表面上看起来 else 后没有任何条件,或者 else if 后只有一个条件—— 但这不是真相:因为 else 的含义是“否则”——else 本身就是一个条件!这也是笔者把 if、else 后代 码块统称为条件执行体的原因,else 的隐含条件对前面条件取反。因此上面代码实际上可改写为: 74
程序清单:codes/04/4-2/TestIfError2.java public class TestIfError { public static void main(String[] args) { int age = 45; if (age > 20) { System.out.println("青年人"); } //在原本的 if 条件中增加了 else 的隐含条件 else if (age > 40 && !(age > 20)) { System.out.println("中年人"); } //在原本的 if 条件中增加了 else 的隐含条件 else if (age > 60 && !(age > 20) && !(age > 40 && !(age > 20))) { } System.out.println("老年人"); } } 此时就比较容易看出为什么发生上面的错误了,对于 age > 40 && !(age > 20)这个条件,又可改写 成 age > 40 && age <= 20,这样情况永远也不会发生了。对于 age > 60 && !(age > 20) && !(age > 40 && !(age > 20))这个条件,则更不可能发生了。因此,无论如何,程序永远都不会判断中年人和老年 人的情形。 为了达到正确的目的,我们把程序改写成如下形式: 程序清单:codes/04/4-2/TestIfCorrect.java public class TestIfCorrect { public static void main(String[] args) { int age = 45; if (age > 60) { } { } System.out.println("老年人"); else if (age > 40) System.out.println("中年人"); else if (age > 20) System.out.println("青年人"); { } } } 运行程序,得到了正确结果。实际上,上面程序等同于下面代码: public class TestIfCorrect public static void main(String[] args) { int age = 45; { 75
疯狂 讲义 if (age > 60) { System.out.println("老年人"); } //在原本的 if 条件中增加了 else 的隐含条件 else if (age > 40 && !(age >60)) { System.out.println("中年人"); } //在原本的 if 条件中增加了 else 的隐含条件 else if (age > 20 && !(age > 60) && !(age > 40 && !(age >60))) System.out.println("青年人"); { } } } 上面程序的判断逻辑即转为如下三种情形:  age 大于 60 岁,判断为“老年人”。  age 大于 40 岁,且 age 小于等于 60 岁,判断为“中年人”。  age 大于 20 岁,且 age 小于等于 40 岁,判断为“青年人”。 上面的判断逻辑才是实际希望的判断逻辑。因此,当我们使用 if...else 语句进行流程控制时,一定 不要忽略了 else 所带的隐含条件。 如果每次都去计算 if 条件和 else 条件的交集也是一件非常烦琐的事情,为了避免出现上面的错误, 在使用 if...else 语句有一条基本规则:总是优先把包含范围小的条件放在前面处理。如 age>60 和 age>20 两个条件,明显 age>60 的范围更小,所以应该先处理 age>60 的情况。 使用 if...else 语句时,一定要先处理包括范围更小的情况。 4.2.2 switch 分支语句 switch 语句由一个控制表达式和多个 case 标签组成,和 if 语句不同的是,switch 语句后面的控制 表达式的数据类型只能是整型,不能是 boolean 型。case 标签后紧跟一个代码块,case 标签作为这个 代码块的标识。switch 语句的语法格式如下: switch (expression) { case condition1: { } statement(s) break; case condition2: { statement(s) break; } ... case conditionN: { } statement(s) break; 76
default: { } } statement(s) 这种分支语句的执行是先对 expression 求值,然后依次匹配 condition1,condition2...conditionN 等 值,遇到匹配的值即执行对应的执行体;如果所有 case 标签后的值都不与 expression 表达式的值相等, 则执行 default 标前后的代码块。 和 if 语句不同的是,switch 语句中各 case 标签前后代码块的开始点和结束点非常清晰,因此完全 可以省略 case 后代码块的花括号。与 if 语句中 else 类似,switch 语句中 default 标签看似没有条件, 其实是有条件的:条件就是 expression 表达式的值不能与前面任何一个 case 标签后的值相等。 下面程序示范了 switch 语句的用法: 程序清单:codes/04/4-2/TestSwitch.java public class TestSwitch { public static void main(String[] args) { //声明变量 score,并为其赋值为'C' char score = 'C'; //执行 swicth 分支语句 switch (score) { case 'A': System.out.println("优秀."); break; case 'B': System.out.println("良好."); break; case 'C': System.out.println("中"); break; case 'D': System.out.println("及格"); break; case 'F': System.out.println("不及格"); break; default: System.out.println("成绩输入错误"); } } } 运行上面程序,看到输出“中”,这个结果完全正常,字符表达式 score 的值为'C',对应结果为“中”。 值得指出的是,switch 语句中控制表达式的类型只能是 byte、short、char 和 int!不能是字符串, 这与 C#中有所不同。 在 case 标签后的每个代码块后都有一条 break;语句,这个 break;语句有极其重要的意义,Java 的 switch 语句允许省略 case 后代码块的 break;语句,但这种省略可能引入一个陷阱。如果我们把上面程 序中的 break;语句都注释掉,将看到如下运行结果: 中 及格 不及格 77
疯狂 讲义 成绩输入错误 这个运行结果看起来比较奇怪,但这正是由 switch 语句的运行流程决定的:switch 语句会先求出 expression 表达式的值,然后拿这个表达式和 case 标签后的值进行比较,一旦遇到相等的值,程序开始执行 这个 case 标签后代码,不再判断与后面 case、default 标签的条件是否匹配,除非遇到 break;才会结束。 使用 switch 语句时,有两个值得注意的地方:第一个地方是 switch 语句后的 expression 表达式的数据类型叧能是 byte、short、char 和 int 类型;第二个地方是如果省 略了 case 后代码块的 break;时所引入的陷阱。 4.3 循环结构 循环语句可以在满足循环条件的情况下,反复执行某一段代码,这段被重复执行的代码被称为循 环体。当反复执行这段循环体时,需要在合适的时候把循环条件改为假,从而结束循环,否则循环将 一直执行下去,形成死循环。循环语句可能包含如下四个部分:  初始化语句(init_statements):一条或多条语句,这些代码用于完成一些初始化工作,初 始化语句在循环开始之前执行。  循环条件(test_ expression):这是一个 boolean 表达式,这个表达式能决定是否执行循环体。  循环体(body_statements):这个部分是循环的主体,如果循环条件允许,这个代码块将 被重复执行。如果这个代码块只有一行语句,则这个代码块的花括号是可以省略的。  迭代语句(iteration_statements):这个部分在一次循环体执行结束后,对循环条件求值之 前执行,通常用于控制循环条件中的变量,使得循环在合适时候结束。 上面四个部分只是一般分类,并不是每个循环中都非常清晰地分出了上面四个成分。 4.3.1 while 循环语句 while 循环的语法格式如下: [init_statements] while(test_ expression) { } statements; [iteration_statements] while 循环每次执行循环体之前,先对 test_ expression 循环条件求值,如果循环条件为 true,则运 行循环体部分。从上面语法格式中来看,迭代语句 iteration_statements 总是位于循环体的最后,因此 只有当循环体能成功执行完成时,while 循环才会执行 iteration_statements 迭代语句。 从这个意义上来看,while 循环也可被当成条件语句——如果 test_ expression 条件一开始就为 false,则循环体部分将永远不会获得执行。 下面语句示范了一个简单的 while 循环: 程序清单:codes/04/4-3/TestWhile.java public class TestWhile { public static void main(String[] args) { //循环的初始化条件 int count = 0; //当 count 小于 10 时,执行循环体 78
while (count < 10) { System.out.println(count); //迭代语句 count++; } System.out.println("循环结束!"); } } 如果 while 循环的循环体部分和迭代语句合并在一起,且只有一行代码,则可以省略 while 循环后 的花括号。但这种省略花括号的做法,可能降低程序的可读性。 使用 while 循环时,一定要保证循环条件有变成 false 的时候,否则这个循环将成为一个死循环, 永远无法结束这个循环。例如如下代码(程序清单同上): int count = 0; while (count < 10) { System.out.println("不停执行的死循环 " + count); count--; } System.out.println("永远无法跳出的循环体"); 在上面代码中,count 的值越来越小,这将导致 count 值永远小于 10,count < 10 循环条件一直为 true,从而导致这个循环永远无法结束。 除此之外,对于许多初学者而言,使用 while 循环时还有一个陷阱:while 循环的循环条件后紧跟 一个分号。如果有如下程序片段(程序清单同上): int count = 0; //while 后紧跟一个分号,表明循环体是一个分号(空语句) while (count < 10); //下面的代码块与 while 循环已经没有任何关系 { System.out.println("------" + count); count++; } 乍一看上,这段代码片段没有任何问题,但仔细看一下这个程序,不难发现 while 循环的循环条 件表达式后紧跟了一个分号。在 Java 程序中,一个单独的分号表示一个空语句,不作任何事情的空语 句,这意味着这个 while 循环的循环体是空语句。空语句作为循环体也不是最大的问题,问题是当 Java 反复执行这个循环体时,循环条件的返回值没有任何改变,这就成了一个死循环。分号后面的代码块 则与 while 循环没有任何关系。 4.3.2 do while 循环语句 do while 循环与 while 循环的区别在于:while 循环是先判断循环条件,如果条件为真才执行循环 体;而 do while 循环则先执行循环体,然后判断循环条件,如果循环条件为真,则执行下一次循环, 否则中止循环。do while 循环的语法格式如下: [init_statements] statements; [iteration_statements] do { } 79
分享到:
收藏