4. 分支和循环:控制程序的“交通灯”

写代码就像指挥交通。什么时候直行,什么时候转弯,什么时候绕圈,都得靠分支和循环来控制。今天我们就来聊聊 Kotlin 里的这些“交通规则”。

本章核心知识点一览:

  • if 判断语句与运算符
  • if-else 分支结构
  • when 表达式(Kotlin 的 switch 升级版)
  • while 循环与 do-while 循环
  • for 循环与区间
  • break 与 continue 控制循环
Kotlin 分支与循环知识体系 分支结构 • if 语句:单条件判断 • if-else:二选一分支 • when 表达式:多路分支 循环结构 • while 循环:条件前置 • do-while 循环:条件后置 • for 循环:遍历区间/集合 循环控制关键字 • break:跳出整个循环 • continue:跳过本次循环,进入下一次

4.1 if 判断语句:最简单的选择

if 是编程里最基础的判断。说白了就是:如果条件成立,就做某件事

val age = 18
if (age >= 18) {
    println("你已经成年了")
}

这里有个小细节:如果 if 后面只有一行代码,花括号可以省略。但我个人建议永远加上花括号——哪怕只有一行。为什么?因为我在项目中见过太多次因为省略花括号导致的 bug,后来加需求时忘了补括号,结果逻辑全乱套了。

4.2 运算符:判断的“工具包”

写判断离不开运算符。Kotlin 的运算符和其他语言大同小异,但有几个地方值得注意。

类型运算符示例说明
比较==, !=a == b比较值是否相等(不是引用)
比较>, <, >=, <=a > b大小比较
逻辑&&, ||, !a > 0 && b > 0与、或、非
区间..1..10包含两端,1 到 10
包含in, !inx in 1..10判断是否在区间内

💡 避坑指南:Kotlin 的 == 相当于 Java 的 equals(),比较的是内容。而 === 才是比较引用地址。我曾经帮同事排查过一个 bug,他用 == 比较两个字符串对象,结果一直 false——其实是两个不同对象但内容相同。换成 == 就对了。

4.3 if-else 语句:二选一

现实世界很少只有一种情况。if-else 就是用来处理“要么 A,要么 B”的场景。

val score = 85
if (score >= 60) {
    println("及格了")
} else {
    println("不及格")
}

Kotlin 有个很酷的特性:if-else 可以作为表达式返回值。这意味着你可以直接赋值。

val result = if (score >= 60) "及格" else "不及格"
println(result)  // 输出:及格

嗯,这里要注意:作为表达式时,if 和 else 的最后一个表达式就是返回值。如果只有 if 没有 else,就不能当表达式用——编译器会报错。

4.4 when 表达式:多路分支的优雅写法

如果你有多个分支要判断,用 if-else 链会写得很长。这时候 when 就派上用场了。它比 Java 的 switch 强大得多。

val day = 3
val dayName = when (day) {
    1 -> "星期一"
    2 -> "星期二"
    3 -> "星期三"
    4 -> "星期四"
    5 -> "星期五"
    6, 7 -> "周末"
    else -> "非法输入"
}
println(dayName)  // 输出:星期三

when 还能做区间判断和类型判断,非常灵活。

val x = 15
when (x) {
    in 1..10 -> println("x 在 1 到 10 之间")
    in 11..20 -> println("x 在 11 到 20 之间")
    else -> println("x 超出范围")
}

val obj: Any = "Hello"
when (obj) {
    is String -> println("这是一个字符串,长度:${obj.length}")
    is Int -> println("这是一个整数")
    else -> println("未知类型")
}

⚠️ 注意:when 的分支条件按顺序匹配,匹配到第一个就停止。所以要把更具体的条件放在前面。我曾经在项目中把 else 放在了中间,结果后面的分支永远执行不到——这种 bug 很难查,因为编译器不会报错。

4.5 while 循环:先判断,再执行

while 循环的逻辑很简单:只要条件为真,就一直执行。适合用在循环次数不确定的场景。

var count = 0
while (count < 5) {
    println("第 ${count + 1} 次循环")
    count++
}

do-while 和 while 的区别在于:do-while 至少执行一次,因为条件判断在循环体后面。

var n = 10
do {
    println("至少执行一次,n = $n")
    n++
} while (n < 5)  // 条件不满足,但已经执行了一次

我个人很少用 do-while,但有一种场景很合适:读取用户输入直到合法为止。先读一次,如果不对再继续读。

4.6 for 循环:遍历的利器

Kotlin 的 for 循环主要用来遍历区间、数组或集合。写法非常简洁。

// 遍历 1 到 5
for (i in 1..5) {
    println(i)  // 输出 1 2 3 4 5
}

// 遍历 1 到 4(不包含 5)
for (i in 1 until 5) {
    println(i)  // 输出 1 2 3 4
}

// 倒序遍历
for (i in 5 downTo 1) {
    println(i)  // 输出 5 4 3 2 1
}

// 步长为 2
for (i in 1..10 step 2) {
    println(i)  // 输出 1 3 5 7 9
}

遍历集合也很方便:

val fruits = listOf("苹果", "香蕉", "橘子")
for (fruit in fruits) {
    println(fruit)
}

// 带索引遍历
for ((index, fruit) in fruits.withIndex()) {
    println("第 $index 个水果是 $fruit")
}

💡 我的习惯:遍历集合时尽量用 for 而不是 while。for 循环更安全,不容易出现索引越界的问题。我在项目中见过有人用 while 遍历列表,结果索引写错了,直接抛 IndexOutOfBoundsException。

4.7 break 和 continue:循环的“刹车”与“跳过”

有时候我们不想让循环一直跑到底。break 用来提前结束整个循环,continue 用来跳过当前这次,继续下一次

// break 示例:找到第一个偶数就停止
for (i in 1..10) {
    if (i % 2 == 0) {
        println("找到偶数:$i")
        break  // 跳出循环
    }
}

// continue 示例:只打印奇数
for (i in 1..10) {
    if (i % 2 == 0) {
        continue  // 跳过偶数
    }
    println(i)  // 输出 1 3 5 7 9
}

嵌套循环时,break 和 continue 默认只作用于最内层循环。如果想跳出外层循环,需要配合标签使用。

outer@ for (i in 1..3) {
    for (j in 1..3) {
        if (i == 2 && j == 2) {
            break@outer  // 跳出外层循环
        }
        println("i=$i, j=$j")
    }
}

⚠️ 避坑指南:我曾经在项目里看到有人滥用 break 和 continue,导致循环逻辑变得很难理解。我的建议是:能用 for 循环的区间控制解决的问题,就不要用 break/continue。比如想遍历前 5 个元素,直接用 for (i in 0 until 5) 就好,没必要用 break。

4.8 综合示例:猜数字游戏

把今天学的知识串起来,写个小游戏:

import kotlin.random.Random

fun main() {
    val target = Random.nextInt(1, 101)  // 生成 1 到 100 的随机数
    var guess: Int
    var attempts = 0

    println("猜数字游戏!范围 1 到 100。")

    do {
        print("请输入你的猜测:")
        guess = readLine()?.toIntOrNull() ?: continue  // 输入无效就重试
        attempts++

        when {
            guess < target -> println("太小了,再试试")
            guess > target -> println("太大了,再试试")
            else -> println("恭喜你!猜对了!用了 $attempts 次。")
        }
    } while (guess != target)
}

这个例子用到了 do-while(至少猜一次)、when(多分支判断)、continue(跳过无效输入)。你看,分支和循环组合起来,就能写出有交互的程序了。


分支和循环是编程的基石。说白了,没有它们,程序就只能从头到尾直线执行,什么决策都做不了。我个人觉得,掌握好 if、when、for 这三个,就能解决 90% 的控制流问题。剩下的 while 和 break/continue,在特定场景下才会用到。

多写、多练,慢慢就会形成肌肉记忆。下次写代码时,遇到“要不要做”、“做哪个”、“做几次”这类问题,你自然就知道该用哪个了。