疯狂kotlin讲义连载之流程控制——顺序结构与分支结构 一

359 阅读8分钟
顺序结构

任何编程语言中最常见的程序结构就是顺序结构。顺序结构就是程序从上到下一行行地执行,中间没有任何判断和跳转。

如果Kotlin程序的多行代码之间没有任何流程控制,则程序总是从上向下依次执行,排在前面的代码先执行,排在后面的代码后执行。这意味着:如果没有流程控制,Kotlin程序的语句是一个顺序执行流,从上向下依次执行每条语句。

分支结构

Kotlin提供了两种常见的分支控制结构:if分支和when分支,其中if分支使用布尔表达式或布尔值作为分支条件来进行分支控制,而when分支则更适用于复杂的条件。

一般来说,当条件较为简单且可能的情况很少时,使用if分支;当条件比较复杂且可能的情况很多时,可以考虑使用when分支。


4.2.1 if分支


Kotlinif分支既可作为语句使用,也可作为表达式使用,下面先介绍if作为语句使用的情形。if语句可使用任意表达式作为分支条件来进行分支控制。与Java相似,Kotlinif语句有如下三种形式。

第一种形式:

if (expression) {
statements...
}

第二种形式:
if (expression) {
statements...
}
else {
statements...
}

第三种形式:
if (expression) {
statements...
}
else if (expression) {
statements...
}
...//
可以有零个或多个else if语句

else {//最后的else语句也可以省略

statement...
}

在上面if语句的三种形式中,第二种形式和第三种形式是相通的,如果第三种形式中的else if块不出现,则变成了第二种形式。

在上面的条件语句中,if expressionelse if expression以及else后花括号括起来的多行代码被称为代码块,一个代码块通常被当成一个整体来执行(除非在运行过程中遇到returnbreakcontinue等关键字),因此这个代码块也被称为条件执行体。例如如下程序。

程序清单:
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")


通常建议不要省略ifelseelse if后执行体的花括号,即使条件执行体只有一行代码,也保留花括号会有更好的可读性,而且保留花括号会减少发生错误的可能。例如如下代码,则不能正常执行(程序清单同上)。

//定义变量b,并为其赋值

var b = 5

if (b > 4)


//如果b>4,则执行下面的执行体,只有一行代码作为代码块

println("b大于4")

else

//否则,执行下面的执行体,只有一行代码作为代码块


b--


//对于下面代码而言,它已经不再是条件执行体的一部分,因此总会执行

println("b
不大于
4")


上面代码中以粗体字标识的代码行:println("b不大于4"),总会执行,因为这行代码并不属于else后的条件执行体,else后的条件执行体就是b--这行代码。

注意:ifelseelse 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本身就是一个条件!这也是把ifelse后代码块统称为条件执行体的原因,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>60age>20两个条件,明显age>60的范围更小,所以应该先处理age>60的情况。

注意:使用if...else语句时,一定要先处理包含范围更小的情况。

以上内容节选自《疯狂Kotlin讲义》:一本让您最直接认识Kotlin的疯狂讲义


本书即将于2017年11月发售 敬请期待

往期连载

第十九期:juejin.cn/post/684490…

相关书籍《疯狂Android讲义》item.jd.com/11689014.ht…