Kotlin 控制流
控制流是程序的"神经系统"——决定代码按什么顺序执行。Kotlin 的控制流语法有几个关键改进:if/when/try 都是表达式(有返回值),when 是加强版 switch,for 直接遍历区间和集合(去掉了易错的 C 风格 for)。本篇逐个讲。
1. if 表达式(关键差异)
Kotlin 的 if 不只是语句,更是表达式——有返回值,可以赋值给变量:
// Kotlin 的 if 是【表达式】(有返回值)
val max = if (a > b) a else b
// 多行 if 分支:最后一行是返回值
val result = if (score >= 90) {
println("优秀")
"A"
} else if (score >= 60) {
println("及格")
"B"
} else {
println("不及格")
"C"
}
// 等价于 Java 的三元 ? :,但 Kotlin 没有三元运算符
// 因为 if-else 已经够简洁了
val s = if (x > 0) "正" else "负"这是 Kotlin 比 Java 简洁的根源之一。Java 里要先声明 String result;,再 if-else 各赋值,啰嗦还容易忘记初始化。Kotlin 一行搞定。
注意:Kotlin 没有三元运算符 ?:,因为 if (cond) a else b 已经够简洁了。
2. when 表达式(加强版 switch)
Kotlin 的 when 是 Java switch 的全面升级版——支持值匹配、区间、类型、任意条件,而且能作表达式:
// when:Kotlin 的加强版 switch
val x = 3
val desc = when (x) {
0 -> "零"
1, 2, 3 -> "1-3" // 多个值用逗号
in 4..9 -> "个位" // 区间
in 10..99 -> "两位数"
else -> "其他"
}
// when 是表达式,有返回值;也可以作语句
when (dayOfWeek) {
1, 2, 3, 4, 5 -> println("工作日")
6, 7 -> println("周末")
else -> println("无效")
}
// when 还可以匹配类型(配合 is)
fun describe(obj: Any): String = when (obj) {
is Int -> "整数"
is String -> "字符串"
is List<*> -> "列表"
else -> "未知"
}
// when 甚至可以匹配任意条件(每个分支是 Boolean 表达式)
val n = 15
when {
n % 15 == 0 -> println("FizzBuzz")
n % 3 == 0 -> println("Fizz")
n % 5 == 0 -> println("Buzz")
else -> println(n)
}when 的强大之处:
- 多值匹配:逗号分隔
1, 2, 3 ->。 - 区间匹配:
in 1..10 ->。 - 类型匹配:
is String ->,自动智能转换。 - 任意条件:不带参数时,每个分支是 Boolean 表达式。
- 穷尽检查:用于密封类(sealed class)时,编译器强制你处理所有分支。
对比 Java 12+ 引入的 switch 表达式,Kotlin 的 when 仍然更强大、更优雅,而且已经稳定多年。
3. for 循环(区间与集合遍历)
Kotlin 去掉了 C 风格的 for (int i=0; i<n; i++),改用区间和集合遍历,更安全(不会越界)也更简洁:
// for 循环:遍历区间、集合、数组
for (i in 1..5) print("$i ") // 1 2 3 4 5 (闭区间)
for (i in 1 until 5) print("$i ") // 1 2 3 4 (半开)
for (i in 5 downTo 1) print("$i ") // 5 4 3 2 1 (递减)
for (i in 1..10 step 2) print("$i ") // 1 3 5 7 9 (步长)
// 遍历集合
val list = listOf("苹果", "香蕉", "橙子")
for (fruit in list) {
println(fruit)
}
// 带索引遍历
for ((index, value) in list.withIndex()) {
println("[$index] $value")
}
// 遍历 Map
val map = mapOf("a" to 1, "b" to 2)
for ((key, value) in map) {
println("$key -> $value")
}
// Kotlin 没有 Java 的传统 for(int i=0; i<n; i++)
// 用区间替代,更安全(不会有越界)注意 for 循环的本质是调用对象的 iterator() 方法。任何类只要实现了 operator fun iterator(): Iterator<T> 都能用 for 遍历。
4. while 与 do-while
while 循环行为和 Java/C 一致。条件为 true 就一直跑:
// while 循环:条件为 true 就一直跑
var i = 0
while (i < 5) {
println(i)
i++
}
// do-while:至少跑一次
var n = 0
do {
println(n)
n++
} while (n < 3)
// 实际项目里 while 远不如 for 常用
// 因为大多数场景都能用 for/forEach/map/filter 替代
// while 适合"不确定循环次数"的场景(读 IO、消费队列)实际项目里 while 远不如 for 常用——大多数场景用 forEach、map、filter 等高阶函数替代,代码更声明式。while 适合"循环次数不确定"的场景(读 IO、消费消息队列、轮询)。
5. break、continue 与标签
break(跳出循环)、continue(跳过本次)行为正常。Kotlin 额外支持标签(label),可以指定跳出哪一层:
// break:跳出最近的循环
for (i in 1..10) {
if (i == 5) break
print("$i ") // 1 2 3 4
}
// continue:跳过本次,进入下一次
for (i in 1..10) {
if (i % 2 == 0) continue
print("$i ") // 1 3 5 7 9
}
// 标签(label):break/continue 指定跳出哪一层
outer@ for (i in 1..3) {
for (j in 1..3) {
if (i * j > 4) break@outer // 直接跳出外层
println("i=$i j=$j")
}
}
// return 在 lambda 里默认返回外层函数
// 用标签可以只返回 lambda
listOf(1, 2, 3).forEach lit@{
if (it == 2) return@lit // 只跳过这次 forEach
println(it)
}
// 还有隐式标签:forEach 函数名作标签
listOf(1, 2, 3).forEach {
if (it == 2) return@forEach
println(it)
}标签语法:在循环前 名字@,在 break/continue 后 @名字。看起来像 goto,但只用于循环控制,不会污染代码结构。
6. return 与 lambda 的陷阱
return 在普通函数里很直白,但在 lambda 里有个陷阱:默认 return 是从外层函数返回,不是从 lambda!这点容易让初学者困惑:
// return:从函数返回
fun sum(a: Int, b: Int): Int {
return a + b
}
// 表达式函数体:直接用 = 写返回值
fun double(n: Int) = n * 2
// 单表达式 return
fun isAdult(age: Int): Boolean = age >= 18
// Nothing 返回类型:抛异常的函数
fun fail(msg: String): Nothing {
throw IllegalArgumentException(msg)
}
// 在 lambda 中 return 的"陷阱":
// 默认 return 是从【外层 fun】返回,不是从 lambda 返回!
fun findFirstEven(nums: List<Int>): Int {
nums.forEach {
if (it % 2 == 0) return it // 这个 return 返回的是 findFirstEven
}
return -1
}解决办法:
- 用标签 return:
return@forEach只结束 lambda 当前轮。 - 用匿名函数代替 lambda:匿名函数的 return 只返回自己。
- 用 forEach 而非 for + return:配合
find、any、all等集合函数,避免显式 return。
7. 实战:计算 FizzBuzz
fun fizzBuzz(n: Int): String =
when {
n % 15 == 0 -> "FizzBuzz"
n % 3 == 0 -> "Fizz"
n % 5 == 0 -> "Buzz"
else -> n.toString()
}
fun main() {
for (i in 1..20) {
print("${fizzBuzz(i)} ")
}
println()
}
// 输出: 1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz 16 17 Fizz 19 Buzz 注意 when 不带参数的写法——每个分支都是独立的 Boolean 表达式。这比 Java 的 if-else if 链清晰得多。
8. 实战:猜数字游戏
import kotlin.random.Random
fun main() {
val target = Random.nextInt(1, 101)
var attempts = 0
println("猜一个 1-100 的数字")
while (true) {
print("你的猜测: ")
val input = readlnOrNull()?.toIntOrNull()
if (input == null) {
println("请输入有效数字")
continue
}
attempts++
when {
input < target -> println("小了")
input > target -> println("大了")
else -> {
println("恭喜,${attempts} 次猜对!")
return
}
}
}
}用到了 when、while(true)、可空调用、readlnOrNull。这是 Kotlin 命令行小程序的典型套路。
小结
这一章你掌握了 Kotlin 所有控制流:if/when 表达式、for(区间与集合)、while、break/continue/标签、return 与 lambda。最大的特色是if 和 when 都是表达式,很多 Java 啰嗦的赋值分支代码能合并成一行。下一篇看 Kotlin 的函数——把这些控制流组织成可复用单元。
← 上一篇 Kotlin 运算符
下一篇 Kotlin 函数 →