引言:告别switch-case?迎接when的到来!
如果你从Java、C#或JavaScript的世界来到Kotlin,那么你首先寻找的,很可能就是熟悉的switch-case语句。而这里会有一个惊喜:Kotlin中没有传统的switch-case。取而代之的是,该语言提供了一个更强大、更灵活的工具——when。
在Stack Overflow上,"How to implement switch-case statement in Kotlin" 这个问题获得了数千次浏览。这很正常:开发者习惯了某些结构,并希望找到它们的对应物。但事实是,Kotlin中的when不仅仅是switch的替代品。它是switch的进化版,在底层运行得更智能、更快速。
在本文中,我们不仅会展示如何编写when。我们还将深入底层:了解你的代码被编译成什么,为什么它在某些场景下比switch更快,以及如何100%地利用when。
1. 基本语法:从switch-case到when
首先,来看一个最简单的例子。假设我们有一个经典的Java结构:
// Javaint day = 3;String dayName;switch (day) { case 1: dayName = "星期一"; break; case 2: dayName = "星期二"; break; case 3: dayName = "星期三"; break; default: dayName = "未知日期";}在Kotlin中,它将如下所示:
// Kotlinval day = 3val dayName = when (day) { 1 -> "星期一" 2 -> "星期二" 3 -> "星期三" else -> "未知日期"}这里已经可以看到两个主要优势:
- 无需break — Kotlin在执行完分支后会自动退出代码块。
- 返回一个值 — 可以将结果直接赋值给变量。
2. when的底层工作原理:字节码与优化
现在是最有趣的部分。当你编写when时,Kotlin编译器会分析你的条件,并选择最优的执行方式。让我们深入字节码(大致了解,不涉及过多细节)。
情况1:带常量的when(类似switch-case)
如果你使用when处理整数、字符串或枚举常量,编译器会生成一个跳转表(tableswitch或lookupswitch)。这与Java用于switch-case的机制相同。区别在于,Kotlin会自动完成此操作,无需你参与。
情况2:带任意条件的when
如果你编写类似这样的代码:
when (x) { in 1..10 -> "小" in 11..100 -> "中" else -> "大"}编译器无法使用跳转表。它会生成一个if-else链。但Kotlin会尽可能高效地执行:条件按顺序检查,一旦找到匹配项,执行就会停止。
情况3:无参数的when
这完全是另一种魔法。如果你编写:
when { x > 0 -> "正数" x < 0 -> "负数" else -> "零"}编译器会将其转换为普通的if-else。但语法比嵌套的if要清晰得多。
结论: Kotlin不仅仅是复制switch-case。它会智能地在跳转表和if-else之间进行选择,以使你的代码运行得尽可能快。
3. when的高级功能:switch所不具备的
when能做的远不止比较值。以下是几个杀手级特性:
3.1. 类型检查(智能转换)
fun describe(obj: Any): String = when (obj) { is String -> "长度为${obj.length}的字符串" // 智能转换为String is Int -> "整数" is List<*> -> "包含${obj.size}个元素的列表" else -> "未知类型"}