Kotlin流程控制
【参考文档】
# 1. for循环
# for元素遍历
for (item in array) { // 元素遍历
print(item )
// 1 2 3 4 5
}
2
3
4
Java for-each
循环
for (item : list)
Kotlin也能使用类似形式的循环,区别在于把冒号
:
换成了关键字in
,具体语句形如for (item in list)
下面是Kotlin对数组进行循环处理的代码例子:
fun main(args: Array<String>) {
val poemArray: Array<String> = arrayOf("朝辞白帝彩云间", "千里江陵一日还", "两岸猿声啼不住", "轻舟已过万重山")
for (item in poemArray) {
print("$item,\n")
}
println("========================\n")
for (i in poemArray.indices) {
if (i % 2 == 0) println("${poemArray[i]},")
else println("${poemArray[i]}。")
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
# for下标遍历
Kotlin in
关键字也可以替代for-i
循环
for (i in poemArray.indices) { }
for (i in array.indices) { // 根据下标再取出对应位置的元素
println(i.toString() + "->" + array[i])=
// 0->1
// 1->2,
// 2->3,
// 3->4,
// 4->5
}
2
3
4
5
6
7
8
9
10
然而取消 for (初始; 条件; 增减)
这个规则是有代价的,因为实际开发中往往存在非同一般的需求,比如以下几种情况,Kotlin的 for (i in array.indices)
语句就无法很好地处理:
- 如何设定条件判断的起始值和终止值?
- 每次循环之后的递增值不是1的时候要怎么办?
- 循环方向不是递增而是递减,又如何是好?
- 与条件判断有关的变量不止一个,咋整?
- 循环过程中的变量,在循环结束后还能不能使用?
针对以上情况,其实Kotlin也给出了几个解决办法,代价是多了诸如 until、step、downTo 这样的关键字,具体用法见下列代码:
// 左闭右开区间 [11, 66),合法值包括11,但不包括66
for (i in 11 until 66) { ... }
// 每次默认递增1,这里改为每次递增4
for (i in 23..89 step 4) { ... }
// for循环默认递增,这里使用downTo表示递减
for (i in 50 downTo 7) { ... }
2
3
4
5
6
7
8
可是这些解决办法并不完美,因为业务需求是千变万化的,并非限定在几种固定模式。同时,以上规则容易使人混淆,一旦没搞清until和downTo的开闭区间,在判断边界值时会产生问题。所以更灵活的解决方案是:起止数值、条件判断、循环方向与递增值都应当在代码中明确指定,
for (初始; 条件; 增减)
这个规则固然废除了,但开发者依旧能够使用while语句实现相关功能
# for遍历元素(带索引)
for ((index, item) in array.withIndex()) { // 同时遍历下标 和 元素
println("$index->$item")
// 0->1
// 1->2
// 2->3
// 3->4
// 4->5
}
2
3
4
5
6
7
8
# forEach遍历数组
array.forEach {
println(it)
// 1
// 2
// 3
// 4
// 5
}
2
3
4
5
6
7
8
# forEach增强版
array.forEachIndexed { index, item ->
println("$index:$item")
// 0:1
// 1:2
// 2:3
// 3:4
// 4:5
}
2
3
4
5
6
7
8
# for循环使用小结
for (i in 1..4) print(i) // 打印结果为: "1234"
如果你需要按反序遍历整数可以使用标准库中的 downTo() 函数:
(也可以先array.reverse()翻转)
for (i in 4 downTo 1) print(i) // 打印结果为: "4321"
也支持指定步长:
for (i in 1..4 step 2) print(i) // 打印结果为: "13"
for (i in 4 downTo 1 step 2) print(i) // 打印结果为: "42"
2
3
如果循环中不要最后一个范围区间的值可以使用 until 函数:
for (i in 1 until 10) { // i in [1, 10), 不包含 10
println(i)
}
2
3
# 2. While循环被保留
while循环
val poemArray: Array<String> = arrayOf("朝辞白帝彩云间", "千里江陵一日还", "两岸猿声啼不住", "轻舟已过万重山")
val poem: String = ""
var i: Int = 0
while (i < poemArray.size) {
if (i % 2 == 0) {
println("${poemArray[i]},")
} else {
println("${poemArray[i]}。")
}
i++
}
println("${poem}该诗歌一共有${i}句。")
2
3
4
5
6
7
8
9
10
11
12
do...while循环:同Java
# 3. 实例测试
前面的循环处理其实都还中规中矩,只有内忧没有外患,但要是数组里的诗句本身就不完善,比如有空指针、有空串、有空格串、有多余串等等,此时就得进行诗句的合法性判断,如此方可输出正常的诗歌文字。合法性判断主要由两块代码组成:
- 如果发现有空指针、有空串、有空格串,则忽略此行,即使用关键字continue继续下个循环;
- 如果合法诗句达到四句,则不管是否遍历完成,直接拼好绝句并结束循环,即使用关键字break跳出循环;加入了合法性判断的代码见下,主要演示了
continue
和break
:
fun main(args: Array<String>) {
val poemArray: Array<String?> =
arrayOf("朝辞白帝彩云间", null, "千里江陵一日还", "", "两岸猿声啼不住", " ", "轻舟已过万重山", "送孟浩然之广陵")
var pos: Int = -1
var count: Int = 0
while (pos <= poemArray.size) {
pos++
if (poemArray[pos].isNullOrBlank())
continue
if (count % 2 == 0) {
println("${poemArray[pos]},")
} else {
println("${poemArray[pos]}。")
}
count++
if (count == 4)
break
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 4. goto语句,标签处返回
外层循环加个@标记
fun main(args: Array<String>) {
val poemArray: Array<String?> =
arrayOf("朝辞白帝彩云间", null, "千里江陵一日还", "", "两岸猿声啼不住", " ", "轻舟已过万重山", "送孟浩然之广陵")
var i: Int = 0
var is_found = false
outside@ while (i < poemArray.size) {
var j: Int = 0
val item = poemArray[i];
if (item != null) {
while (j < item.length) {
if (item[j] == '一') {
is_found = true
break@outside
}
j++
}
}
i++
}
println(if (is_found) "我找到'一'字啦" else "没有找到'一'字呀")
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 标签处返回
Kotlin 有函数字面量、局部函数和对象表达式。因此 Kotlin 的函数可以被嵌套。 标签限制的 return 允许我们从外层函数返回。 最重要的一个用途就是从 lambda 表达式中返回。回想一下我们这么写的时候:
fun foo() {
ints.forEach {
if (it == 0) return
print(it)
}
}
2
3
4
5
6
这个 return 表达式从最直接包围它的函数即 foo 中返回。 (注意,这种非局部的返回只支持传给内联函数的 lambda 表达式。) 如果我们需要从 lambda 表达式中返回,我们必须给它加标签并用以限制 return。
fun foo() {
ints.forEach lit@ {
if (it == 0) return@lit
print(it)
}
}
2
3
4
5
6
现在,它只会从 lambda 表达式中返回。通常情况下使用隐式标签更方便。 该标签与接受该 lambda 的函数同名。
fun foo() {
ints.forEach {
if (it == 0) return@forEach
print(it)
}
}
2
3
4
5
6
或者,我们用一个匿名函数替代 lambda 表达式。 匿名函数内部的 return 语句将从该匿名函数自身返回
fun foo() {
ints.forEach(fun(value: Int) {
if (value == 0) return
print(value)
})
}
2
3
4
5
6
当要返一个回值的时候,解析器优先选用标签限制的 return,即
return@a 1
意为"从标签 @a 返回 1",而不是"返回一个标签标注的表达式 (@a 1)"。
# 5. Range范围表达式
# .. 运算符
双点运算符,简化了对范围的表达
fun main(args: Array<String>) {
// 这个范围表示了从 1 到 10
val res = 1..10
}
2
3
4
5
# downTo表达运算符
downTo正好是与双点运算符是相反的
// 这个范围表示了从 10 到 1
val res = 10 downTo 1
2
步长为2的downTo 表达运算符
// 这个范围表示了从 10 到 1,但是步长为 2:即 10、8、6、4、2
val res = 10 downTo 1 step 2
2
# 范围表达式也可表示连续的字符串
// 这个范围表示了从 a 到 z : "a","b","c","d"...."z"
val res = "a".."z"
2
# 可以使用关键字 in 判断范围匹配
// 这个范围表示了从 a 到 z : "a","b","c","d"...."z"
val res = "a".."z"
val contains = "a" in res
2
3
# 范围表达式也可以写作对象的方法
// 这个范围表示了从 1 到 10
val r5 = 1.rangeTo(10)
// 这个范围表示了从 10 到 1
val r6 = 10.downTo(1)
2
3
4
5
# 6. When表达式
kotlin的when其实就是对java的switch的一个升级
switch分支语句
String ans = "B";
switch (ans) {
case "A":
// TODO
break;
case "B":
// TODO
break;
default:
break;
}
2
3
4
5
6
7
8
9
10
11
when分支语句
String ans = "A";
when (ans) {
"A" -> {
// TODO
}
"B" -> {
// TODO
}
else -> {
// TODO
}
}
2
3
4
5
6
7
8
9
10
11
12
当我们的需要的分支枚举完毕,可以使用 else 指向默认分支
fun main(args: Array<String>) {
val x = 7
val numbersList = arrayListOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
when (x) {
in 1..5 -> println("x is in range of 1 to 10")
in numbersList -> print("x in numbersList range")
else -> print("X is not in the range and its value of x is $x")
}
}
2
3
4
5
6
7
8
9
# 不写break的case
fun main(args: Array<String>) {
val x = 1
val numbersList = arrayListOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
when (x) {
in 1..10 -> println("x is in range of 1 to 10")
in numbersList -> print("x in numbersList range") // 此处不会执行
else -> print("X is not in the range and its value of x is $x")
}
}
>>> output: x is in range of 1 to 10
2
3
4
5
6
7
8
9
10
11
不写break的话会接着执行下一个case进行比较么?
- 不是的,这个when的结果是只会执行当前分支的内容,后跳出当前when
如何像java一样不写break的话会执行多个呢?
var num = 6;
when (num) {
in 1..20 -> {
// TODO
}
}
var res = "null"
when (res) {
is String -> {
// TODO
}
}
2
3
4
5
6
7
8
9
10
11
12
13
- is 就是 Java的
instanceof
- as 就是用来强制类型转换的
# 结合范围表达式
# 范围表达式取非
fun main(args: Array<String>) {
val x = 15
when (x) {
!in 10..20 -> print("x is outside the range")
else -> print("none of the above")
}
}
>>> output: none of the above
2
3
4
5
6
7
8
9
# when表达式嵌套语句示例
fun main(args: Array<String>) {
val x = 10
val y = 7
val z = 20
val result = when (z) {
20 -> {
println("if z id 20 then doing the sum of x and y")
x + y
}
30 -> {
println("if z id 30 then subtracting y from x")
x - y
}
else -> "none of the value matched"
}
println("The result is $result")
}
>>> output: if z id 20 then doing the sum of x and y
The result is 17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 7. 三目运算符
fun maxOf(a: Int, b: Int) = if (a > b) a else b
Tips:如果你使用if作为表达式而不是语句(例如:返回它的值或者把它赋给变量),该表达式需要有 else分支。
【原文转载】:
[1] aqi00. Kotlin入门(7)循环语句的操作[EB/OL]. https://www.cnblogs.com/aqi00/p/7192967.html
[2] 苗小帅. Kotlin之流程控制[EB/OL]. https://www.jianshu.com/p/01eaac5f8767