流程控制语句是编程语言中的核心之一。可以分为 分支语句、循环语句和跳转语句。下面我们深入的了解Kotlin的流程控制语句。
if
if-else语句是控制程序流程的最基本的形式,其中else是可选的。
在Kotlin中,if是表达式,比如它可以返回一个值。 是除了condition ? then : else)之外的唯一一个三元表达。
传统用法
val a = 10
val b = 20
var max_0: Int = a
if (a > b) {
max_0 = a
} else {
max_0 = b
}
println("----------------------------------")
println("max_0:$max_0")
println("----------------------------------")
// Log
--------------
max_0:20
--------------
作为表达式
var max_1 = if (a > b) a else b
println("--------------")
println("max_1:$max_1")
println("--------------")
//Log
--------------
max_1:20
--------------
作为代码块
println("--------------")
val max_2 = if (a > b) {
println("Choose a")
a
} else {
println("Choose b")
b
}
println("max_2:$max_2")
println("--------------")
// Log
--------------
Choose b
max_2:20
--------------
if作为代码块时,最后一行必须为该块的返回值.
如果 if 表达式只有一个分支, 或者分支的结果是 Unit , 它的值就是 Unit 。
if-else语句规则:
- if后的括号不能省略,括号里表达式的值最终必须返回的是布尔值
- 如果条件体内只有一条语句需要执行,那么if后面的大括号可以省略,但这是一种极为不好的编程习惯。
- 对于给定的if,else语句是可选的,else if 语句也是可选的
- else和else if同时出现时,else必须出现在else if 之后
- 如果有多条else if语句同时出现,那么如果有一条else if语句的表达式测试成功,那么会忽略掉其他所有else if和else分支。
- 如果出现多个if,只有一个else的情形,else子句归属于最内层的if语句
when
when取代了C风格语言的switch。相较switch而言,when语句显得更加的强大,灵活性更好。
when会对所有的分支进行检查直到有一个条件满足。 when 可以用做表达式或声明。如果用作表达式的话,那么满足条件的分支就是总表达式。如果用做声明,不满足条件的分支的的的值会被忽略,只保留满足条件的分支,而且返回的值也是最后一个表达式的值。
传统用法
val x : Int = 10
when (x) {
9 -> println("x:${x + 10}")
10 -> println("x:$x")
else -> print("x:$x")
}
分支条件一致
如果有分支可以用同样的方式处理的话, 分支条件可以连在一起处理。
when (x) {
0,1 -> print("x == 0 or x == 1")
else -> print("otherwise")
}
使用任意表达式作为分支的条件
when (x) {
parseInt(s) -> print("s encode x")
else -> print("s does not encode x")
}
when (x) {
in 1..10 -> print("x is in the range")
in validNumbers -> print("x is valid")
!in 10..20 -> print("x is outside the range")
else -> print("none of the above")
}
作为表达式
val hasPrefix = when (x) {
is String -> x.startsWith("prefix")
else -> false
}
for
for 循环通过任何提供的迭代器进行迭代。 语法如下:
for (item in collection)
print(item)
如果遍历list或者array可以通过索引进行迭代:
for (i in array.indices)
print(array[i])
while循环
while语句
while语句在循环刚开始时,会计算一次布尔表达式的值,如果满足条件,进入循环,如果不满足条件,将跳出循环。而在while语句的下一次迭代开始前会计算再一次布尔值,如此重复。
while (x > 0) {
x--
}
#dowhile语句
dowhile语句与while语句类是,唯一的区别是doWhile语句会至少执行一次,即便布尔表达式的第一次计算就是false.而while语句中,如果 布尔表达式的第一次计算的值是false,该循环不会执行。
do {
val y = retrieveData()
} while (y != null) // y 在这是可见的
返回与跳转
Kotlin中有return、break、continue等三种返回跳转操作符。
-
return
-
指定一个方法返回什么值
-
导致当前方法结束,并返回返回指定的值
fun main(args: Array<String>) { println("testA:${testA(10)}") println("----------") println("testB:${testB(10)}") } fun testA(a : Int):Int{ if (a > 0) { return -1 } else { return 1 } } fun testB(a : Int):Int{ println("a:$a") if (a > 0) { return -1 } else { return 1 } a++ print("a:$a") } // Log打印 testA:-1 ---------- a:10 testB:-1
-
-
break
结束最近的闭合循环,不执行循环中剩余的语句val arraysA = listOf("A", "B", "C", "D") val arraysB = listOf(1,2,3,4) for (itemA in arraysA) { for (itemB in arraysB) { if (itemB > 2) { break } println("itemB:$itemB") } if (itemA == "C") { break } println("itemA:$itemA") } // Log itemB:1 itemB:2 itemA:A itemB:1 itemB:2 itemA:B itemB:1 itemB:2
从Log打印可以看出,第一个break结束的是for (itemB in arraysB)这个循环,而第二个break结束的是for (itemA in arraysA),它们的共通点就是结束都是距离它们最近的一个循环。
-
continue
跳到最近的闭合循环的下一次循环val arraysA = listOf("A", "B", "C", "D") val arraysB = listOf(1,2,3,4) for (itemA in arraysA) { var i : Int = 0 for (itemB in arraysB) { i++ if (itemB > 2) { continue } println("itemB:$itemB") } if (itemA == "C") { continue } println("i:$i") println("itemA:$itemA") println("---------") } // Log itemB:1 itemB:2 i:4 itemA:A --------- itemB:1 itemB:2 i:4 itemA:B --------- itemB:1 itemB:2 itemB:1 itemB:2 i:4 itemA:D ---------
从上述Log上,可以清楚看到,两个循环分别循环了四次,但是在碰到continue时,会跳出当前循环并执行下一次循环。
#标签
在 Kotlin 中表达式可以添加标签,标签通过@结尾来表示,比如:abc@,fooBar@
loop@ for (i in 1..100){
//...
}
break和标签
loop@ for (itemA in arraysA) {
var i : Int = 0
for (itemB in arraysB) {
i++
if (itemB > 2) {
break@loop
}
println("itemB:$itemB")
}
println("i:$i")
println("itemA:$itemA")
println("---------")
}
// Log打印
itemB:1
itemB:2
从Log打印,第一个循环执行了一次,第二个循环执行了两次,便跳出了封闭的循环。意味着break跳到标签后边的表达式,并不再执行此表达式直接跳过,执行后边的语句。
continue和标签
loop@ for (itemA in arraysA) {
var i : Int = 0
for (itemB in arraysB) {
i++
if (itemB > 2) {
continue@loop
}
println("itemB:$itemB")
}
println("i:$i")
println("itemA:$itemA")
println("---------")
}
// Log打印
itemB:1
itemB:2
itemB:1
itemB:2
itemB:1
itemB:2
itemB:1
itemB:2
之前说过,continue是跳到最近的闭合循环的下一次循环,但是加上标签以后,直接跳转到了第一个循环,也就是for (itemA in arraysA),并没有执行最近的闭合循环的下一次循环。意味着continue直接跳转到标签后面的语句并执行。
return和标签
val ints = listOf(0, 1, 2, 3)
fun main(args: Array<String>) {
foo()
}
fun foo() {
ints.forEach {
if (it ==0) return@forEach
println(it)
}
}
// Log打印
1
2
3
fun foo() {
ints.forEach {
if (it ==0) return@forEach
print(it)
}
}
从Log打印可以看出,return会跳转到标签后边的表达式处,并执行该表达式。
命名函数自动定义标签
fun outer(){
var i: Int = run {
return@run 1
}
i = run {
return@outer
}
}
作用域
从作用域来看,标签和变量是一致的,都有相对应的作用于。在main方法里面定义了一个标签list@,在foo方法里面调用时,提示“Unresolved reference:@list”,意味着list标签的作用域应该在main方法里,在foo方法里并不能够调用。