顺序结构
任何编程语言中最常见的程序结构就是顺序结构。顺序结构就是程序从上到下一行行地执行,中间没有任何判断和跳转。
如果
Kotlin
程序的多行代码之间没有任何流程控制,则程序总是从上向下依次执行,排在前面的代码先执行,排在后面的代码后执行。这意味着:如果没有流程控制,
Kotlin
程序的语句是一个顺序执行流,从上向下依次执行每条语句。
分支结构
Kotlin
提供了两种常见的分支控制结构:
if
分支和
when
分支,其中
if
分支使用布尔表达式或布尔值作为分支条件来进行分支控制,而
when
分支则更适用于复杂的条件。
一般来说,当条件较为简单且可能的情况很少时,使用
if
分支;当条件比较复杂且可能的情况很多时,可以考虑使用
when
分支。
4.2.1 if分支
Kotlin
的
if
分支既可作为语句使用,也可作为表达式使用,下面先介绍
if
作为语句使用的情形。
if
语句可使用任意表达式作为分支条件来进行分支控制。与
Java
相似,
Kotlin
的
if
语句有如下三种形式。
第一种形式:
if (expression) {
statements...
}
第二种形式:
if (expression) {
statements...
}
else {
statements...
}
第三种形式:
if (expression) {
statements...
}
else if (expression) {
statements...
}
...//
可以有零个或多个
else if
语句
else {//最后的else语句也可以省略
statement...
}
在上面
if
语句的三种形式中,第二种形式和第三种形式是相通的,如果第三种形式中的
else if
块不出现,则变成了第二种形式。
在上面的条件语句中,
if expression
、
else if expression
以及
else
后花括号括起来的多行代码被称为代码块,一个代码块通常被当成一个整体来执行(除非在运行过程中遇到
return
、
break
、
continue
等关键字),因此这个代码块也被称为条件执行体。例如如下程序。
程序清单:
codes\04\4.2\IfTest.kt
fun main(args: Array<String>) {
var age = 30
if (age > 20) {
//
只有当
age > 20
时,下面花括号括起来的语句块才会执行
//
花括号括起来的语句是一个整体,要么一起执行,要么一起不会执行
println("
年龄已经大于
20
岁了
")
println("20
岁以上的人应该学会承担责任
...")
}
}
如果
if(logic expression)
、
else if(logic expression)
和
else
后的代码块只有一行语句时,则可以省略花括号,因为单行语句本身就是一个整体,无须用花括号来把它们定义成一个整体。下面代码完全可以正常执行(程序清单同上)。
//
定义变量
a
,并为其赋值
val a = 5
if (a > 4)
//
如果
a>4
,则执行下面的执行体,只有一行代码作为代码块
println("a
大于
4")
else
//
否则,执行下面的执行体,只有一行代码作为代码块
println("a
不大于
4")
通常建议不要省略
if
、
else
、
else if
后执行体的花括号,即使条件执行体只有一行代码,也保留花括号会有更好的可读性,而且保留花括号会减少发生错误的可能。例如如下代码,则不能正常执行(程序清单同上)。
//
定义变量
b
,并为其赋值
var b = 5
if (b > 4)
//
如果
b>4
,则执行下面的执行体,只有一行代码作为代码块
println("b
大于
4")
else
//
否则,执行下面的执行体,只有一行代码作为代码块
b--
//
对于下面代码而言,它已经不再是条件执行体的一部分,因此总会执行
println("b
不大于
4")
上面代码中以粗体字标识的代码行:
println("b
不大于
4")
,总会执行,因为这行代码并不属于
else
后的条件执行体,
else
后的条件执行体就是
b--
这行代码。
注意:
if
、
else
、
else if
后的条件执行体要么是一个花括号括起来的代码块,则这个代码块整体作为条件执行体;要么单独的一行语句,甚至可能是一个空语句(空语句是一个分号),那么就只是这条语句作为条件执行体。如果省略了
if条件后条件执行体的花括号,那么if条件只控制紧跟该条件语句的一条语句。
如果
if
后有多条语句作为条件执行体,若省略了这个条件执行体的花括号,则会引起编译错误。看下面代码(程序清单同上):
//
定义变量
c
,并为其赋值
var c = 5
if (c > 4)
//
如果
c>4
,则执行下面的执行体,将只有
c--
一行代码为执行体
c--
//
下面是一行普通代码,不属于执行体
println("c
大于
4")
//
此处的
else
将没有
if
语句,因此编译出错
else
//
否则,执行下面的执行体,只有一行代码作为代码块
println("c
不大于
4")
在上面代码中,因为
if
后的条件执行体省略了花括号,则系统只把
c--
一行代码作为条件执行体,当
c--
语句结束后,
if
语句也就结束了。后面的
println("c
大于
4")
代码已经是一行普通代码了,不再属于条件执行体,从而导致
else
语句没有
if
语句,从而引起编译错误。
对于
if
分支,还有一个很容易出现的逻辑错误,这个逻辑错误并不属于语法问题,但引起错误的可能性更大。看下面程序:
程序清单:
codes\04\4.2\IfErrorTest.kt
fun main(args: Array<String>)
{
var age = 45
if (age > 20){
println("
青年人
")
}
else if (age > 40)
{
println("
中年人
")
}
else if (age > 60)
{
println("
老年人
")
}
}
表面上看起来,上面的程序没有任何问题:人的年龄大于
20
岁是青年人,年龄大于
40
岁是中年人,年龄大于
60
岁是老年人。但运行上面程序,发现打印结果是:青年人,而实际上希望
45
岁应判断为中年人——这显然出现了一个问题。
对于任何的
if else
语句,表面上看起来
else
后没有任何条件,或者
else if
后只有一个条件——但这不是真相:因为
else
的含义是“否则”——
else
本身就是一个条件!这也是把
if
、
else
后代码块统称为条件执行体的原因,
else
的隐含条件是对前面条件取反。因此,上面代码实际上可改写为:
程序清单:
codes\04\4.2\IfErrorTest2.kt
fun main(args: Array<String>) {
var age = 45
if (age > 20) {
println("
青年人
")
}
//
在原本的
if
条件中增加了
else
的隐含条件
if (age > 40 && !(age > 20))
{
println("
中年人
")
}
//
在原本的
if
条件中增加了
else
的隐含条件
if (age > 60 && !(age > 20) && !(age > 40 && !(age > 20)))
{
println("
老年人
")
}
}
此时就比较容易看出为什么发生上面的错误了。对于
age > 40 && !(age > 20)
这个条件,又可改写成
age > 40 && age <= 20
,这样永远也不会发生了。对于
age > 60 && !(age > 20) && !(age > 40 && !(age > 20))
这个条件,则更不可能发生了。因此,程序永远都不会判断中年人和老年人的情形。
为了达到正确的目的,可以把程序改为如下形式。
程序清单:codes\04\4.2\IfCorrectTest.kt
fun main(args: Array<String>) {
var age = 45
if (age > 60) {
println("
老年人
")
}
else if (age > 40) {
println("
中年人
")
}
else if (age > 20) {
println("
青年人
")
}
}
运行程序,得到了正确结果。实际上,上面程序等同于下面代码。
程序清单:
codes\04\4.2\IfCorrectTest2.kt
fun main(args: Array<String>) {
var age = 45
if (age > 60)
{
println("
老年人
")
}
//
在原本的
if
条件中增加了
else
的隐含条件
if (age > 40 && !(age >60))
{
println("
中年人
")
}
//
在原本的
if
条件中增加了
else
的隐含条件
if (age > 20 && !(age > 60) && !(age > 40 && !(age >60)))
{
println("
青年人
")
}
}
上面程序的判断逻辑即转为如下三种情形。
1、
age大于60
岁,判断为
“老年人”。
2、
age大于40岁,且age小于等于60
岁,判断为
“中年人”。
3、
age大于20岁,且age小于等于40
岁,判断为
“青年人”。
上面的判断逻辑才是实际希望的判断逻辑。因此,当使用
if...else
语句进行流程控制时,一定不要忽略了
else
所带的隐含条件。
如果每次都去计算
if
条件和
else
条件的交集也是一件非常烦琐的事情,为了避免出现上面的错误,在使用
if...else
语句时有一条基本规则:总是优先把包含范围小的条件放在前面处理。如
age>60
和
age>20
两个条件,明显
age>60
的范围更小,所以应该先处理
age>60
的情况。
注意:使用
if...else
语句时,一定要先处理包含范围更小的情况。
以上内容节选自《疯狂Kotlin讲义》:一本让您最直接认识Kotlin的疯狂讲义
往期连载
相关书籍《疯狂Android讲义》
item.jd.com/11689014.ht…