顺序结构
任何编程语言中最常见的程序结构就是顺序结构。顺序结构就是程序从上到下一行行地执行,中间没有任何判断和跳转。
如果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…