选择结构
程序可以基于条件决定执行哪些语句。
和所有高级程序设计语言一样,Java 也提供选择语句:在可选择的执行路径中做出选择的语句。选择语句要用到采用布尔表达式的条件。布尔表达式是计算结果为 Boolean 值:true 或者 false 的表达式。
boolean 数据类型
boolean 数据类型声明一个具有值 true 或者 false 的变量。
Java 提供六种关系操作符(relational operator),也称为比较操作符(comparison operator),用于两个值的比较。比较的结果是一个布尔值:true(真)或 false(假)。
关系操作符如下表:
操作符 | 数学符号 | 名称 |
---|---|---|
< | < | 小于 |
<= | ≤ | 小于等于 |
> | > | 大于 |
>= | ≥ | 大于等于 |
== | = | 等于 |
!= | ≠ | 不等于 |
警告: 相等的关系操作符是两个等号(==),而不是一个等号(=),后者是指赋值操作符。
具有布尔值的变量称为布尔变量(boolean variable),boolean 数据类型用于声明布尔型变量。boolean 型变量可以是以下这两个值中的一个:true 和 false 。
注意: true 和 false 都是直接量,它们被当作保留字一样,不能用做程序中的标识符。
if 语句
if 语句是一个结构,允许程序确定执行的路径
Java 有几种类型的选择语句:单分支 if 语句、双分支 if - else 语句、嵌套 if 语句、多分支 if-else 语句、switch 语句和条件表达式。
单分支 if 语句
单分支 if 语句是指当且仅当条件为 true 时执行一个动作。单分支 if 语句的语法如下:
if(布尔表达式){
语句(组);
}
流程图是描述算法或者过程的图,以各种盒子显示步骤,并且通过箭头连接给出次序。处理操作显示在这些框中,连接它们的箭头代表控制流程。棱形框表示一个布尔类型的条件,矩形框代表语句。
单分支 if 语句的流程图如下:
if 语句在布尔表达式计算结果为 true 的情况下执行语句组。
提示: 布尔表达式应该用括号括住。如果花括号内只有一条语句,则可以省略花括号。
注意: 省略括号可以让代码更加简短,但是容易产生错误。当修改省略花括号的代码时,容易忘记加上括号。
双分支 if-else 语句
if-else 语句根据条件是真或者是假,决定执行的路径。
单分支 if 语句当指定条件为 true 时执行一个操作,而当条件为 false 时什么也不干。使用双分支 if 语句。根据条件为 true 或 false ,双分支 if 语句可以指定不同的操作。下面是双分支 if-else 语句的语法:
if (布尔表达式) {
布尔表达式为真时执行的语句(组);
} else {
布尔表达式为假时执行的语句(组);
}
双分支 if-else 语句的流程图如下:
如果布尔表达式的计算结果为 true ,则执行条件为 true 时该执行的语句;否则,执行条件为 false 时该执行的语句。
嵌套的 if 语句和多分支 if-else 语句
if 或 if-else 语句中的语句可以是任意合法的 Java 语句,也可以是其他的 if 或 if-else 语句。内层 if 语句称为是嵌套在外层 if 语句里的。内层 if 语句还可以包含其他的 if 语句。事实上,对嵌套的深度没有限制。
嵌套的 if 语句可用于实现多重选择。else 和 if 写在同一行是推荐使用的多重选择 if 语句的书写风格,这种风格,称为多分支 if-else 语句,可以避免深度缩进,并使程序易于阅读。
常见错误和陷阱
忘记必要的括号,在错误的地方结束 if 语句,将 == 错当作 = 使用,悬空 else 分支,是选择语句中常见的错误。if-else 语句中重复的语句,以及测试双精度值的相等是常见的陷阱 。
常见错误 1 :忘记必要的括号
如果块中只有一条语句,就可以忽略花括号。但是,当需要用花括号将多条语句括在一起时,忘记花括号是一个常见的程序设计错误。如果通过在没有花括号的 if 语句中添加一条新语句来修改代码,就必须插入花括号。
常见错误 2 :在 if 行出现错误的分号
在 if 行加上了一个分号,这是一个常见错误。这个错误是很难发现的,因为它既不是编译错误也不是运行错误,而是一个逻辑错误。使用行尾块风格可帮助防止出现此类错误。
常见错误 3 :对布尔值的冗余测试
为了检测测试条件中的布尔型变量是 true 还是 false ,使用相等比较操作符是多余的,替代方法是直接测试布尔变量。这样做也可以避免出现使用 = 操作符而不是 == 操作符去比较测试条件中的两项是否相等的错误。 这样虽然没有编译错误,但是使用 = 操作符而不是用 == 比较布尔型变量,只会测试后面的布尔值。而且前者是赋值操作符,前面的布尔型变量值也可能变化。
常见错误 4 :悬空 else 出现的歧义
在嵌套的 if-else 语句中,如果不加花括号,容易产生悬空 else 歧义。在同一个块中,else 总是和离它最近的 if 子句匹配。如果 else 要和较远的 if 匹配,要加上正确的花括号。
常见错误 5 :两个浮点数值的相等测试
浮点数具有有限的计算精度;涉及浮点数的计算可能引人取整错误。因此,两个浮点数值的相等测试并不可靠。虽然不能依赖于两个浮点数值的相等测试,但是可以通过测试两个数的差距小于某个阈值,来比较它们是否已经足够接近。也就是,对于一个非常小的值
ε
\varepsilon
ε ,如果
∣
x
−
y
∣
<
ε
|x-y|<\varepsilon
∣x−y∣<ε ,那么
x
x
x 和
y
y
y 非常接近。
ε
\varepsilon
ε 常用于表示一个非常小的值。通常,将
ε
\varepsilon
ε 设为 10-14 来比较两个 double 类型的值,而设为 10-7 来比较两个 float 类型的值。
常见陷阱 1 :简化布尔变量赋值
编写将一个条件测试賦给 boolean 变量的代码。
常见陷阱 2 :避免不同情形中的重复代码
经常会在不同情形中写重复的代码,这些代码应该写在一处的。
产生随机数
使用 Math.random() 来获得一个 0.0 到 1.0 之间的随机 double 值,不包括 1.0 。
也可以使用 Systems.currentTimeMillis() 产生随机数。
程序结束
System.exit(status) 是在 System 类中定义的,调用这个方法可以终止程序。参数 status 为 0 表明程序正常结束。一个非 0 的状态代码表示非正常结束。
测试程序
为了测试程序,应该提供覆盖所有情况的输人。
对所有的程序都应该先编写少量代码然后进行测试,之后再继续添加更多的代码。这个过程称为递进式开发和测试(incremental development and testing)。这种方法使得调试变得更加容易,因为错误很可能就在你刚刚添加进去的新代码中 。
逻辑操作符
逻辑操作符 !、&& 、|| 和 ^ 可以用于产生复合布尔表达式。
有时候,是否执行一条语句是由几个条件的组合来决定的。可以使用逻辑操作符组合这些条件。 逻 辑操作符(logical operator)也称为布尔操作符(boolean operator),是对布尔值进行的运算,它会创建新的布尔值。
操作符 ! 的真值表
p | !p |
---|---|
true | false |
false | true |
非操作符(!)对 true 取反是 false ,而 false 取反之后则是 true 。
操作符 && 的真值表
p1 | p2 | p1&&p2 |
---|---|---|
false | false | false |
false | true | false |
true | false | false |
true | true | true |
当且仅当两个操作数都为 true 时,这两个布尔型操作数的与(&&)为 true 。
操作符 || 的真值表
p1 | p2 | p1||p2 |
---|---|---|
false | false | false |
false | true | true |
true | false | true |
true | true | true |
当至少有一个操作数为 true 时,两个布尔型操作数的或(||)为 true 。
p1 | p2 | p1^p2 |
---|---|---|
false | false | false |
false | true | true |
true | false | true |
true | true | false |
当且仅当两个操作数具有不同的布尔值时,两个布尔型操作数的异或(^)才为 true 。
注意: pl^p2 等同于 pl!=p2 。
注意 : 德模佛定理可以用来简化表达式。
!(conditionl && condition2) 和 !conditionl || !condition 2 是等价的。
!(conditionl || condition2) 和 !conditionl && !condition 2 是等价的。
如果操作符 && 的操作数之一为 false ,那么表达式就是 false ;如果操作符 || 的操作数之一为 true,那么表达式就是 true 。Java 利用这些特性来提高这些操作符的效率。在编程术语中,&& 和 || 被称为短路或者懒惰操作符。 Java 也提供了无条件 AND(&)和 OR(|) 操作符
插播:如果某年可以被 4 整除而不能被 100 整除,或者可以被 400 整除,那么这一年就是闰年。
switch 语句
switch 语句基于变量或者表达式的值来执行语句。
为了全面考虑所有的情况,需要使用嵌套的 if 语句,但是过多地使用嵌套的 if 语句会使程序很难阅读。 Java 提供 switch 语句来有效地处理多重条件的问题。
switch 语句的完整语法:
switch ( switch 表达式 ) {
case 值 1 : 语句(组)1;
break;
case 值 2 : 语句(组)2;
break;
case 值 N : 语句(组)N;
break;
default:默认情况下执行的语句(组);
}
switch 语句遵从下述规则:
- switch 表达式必须能计算出一个 char 、byte 、short、int 或者 String 型值,并且必
须总是要用括号括住。 - valuel ,… ,valueN 必须与 switch 表达式的值具有相同的数据类型 。注意:valuel ,… ,valueN 都是常量表达式,不能包含变量。
- 当 switch 表达式的值与 case 语句的值相匹配时,执行从该 case 开始的语句,直到遇到一个 break 语句或到达该 switch 语句的结束。
- 默认情况(default)是可选的,当没有一个给出的 case 与 switch 表达式匹配时,用来执行该操作。
- 关键字 break 是可选的。break 语句会立即终止 switch 语句。
警告: 不要忘记在需要的时候使用 break 语句。一旦匹配其中一个 case ,就从匹配的case 处开始执行,直到遇到 break 语句或到达 switch 语句的结束。 这种现象称为落空行
为(fall-through behavior)。
提示: 为了避免程序设计错误,提高代码的可维护性,如果省略 break ,在 case 子句
后添加注释。
条件表达式
条件表达式基于一个条件计算表达式的值。有时可能需要给有特定条件限制的变量赋值。使用条件表达式可以编写精简的代码。
条件表达式是一种完全不同的风格,在语句中没有明确出现 if 。该语法如下所示:
//(布尔表达式 ? 表达式 1 : 表达式 2)
boolean-expression ? expressionl : expression2;
如果布尔表达式的值为 true ,则条件表达式的结果为表达式 expressionl ;否则,结果为表达式 expression2 。
注意: 符号 ? 和 : 在条件表达式中同时出现。它们构成一种条件操作符,因为操作数有三
个,所以称为三元操作符(ternary operator)。它是 Java 中唯一的三元操作符。
操作符的优先级和结合规则
操作符的优先级和结合规则确定了操作符计算的顺序。
首先计算括号中的表达式(括号可以嵌套,在嵌套的情况下,先计算里层括号中的表达式)。当计算没有括号的表达式时,操作符会依照优先级规则和结合规则进行运算。
优先级规则定义了操作符的先后次序。逻辑操作符的优先级比关系操作符的低 ,而关系操作符的优先级比算术操作符的低 。优先级相同的操作符排在同一行。
如果优先级相同的操作符相邻,则结合规则( associativity)决定它们的执行顺序。除了赋值操作符之外,所有的二元操作符都是左结合的(left-associative),赋值操作符是右结合的(right-associative)。左结合对赋值操作符而言是说不通的。
注意: Java 有自己内部计算表达式的方式。Java 计算的结果和它对应的算术计算是一样的。