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

顺序结构

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

如果 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的疯狂讲义


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

往期连载

第十九期:juejin.im/post/5a13bc…

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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值