彻底讲清楚 Kotlin 的 when 表达式

一、一句话理解 when

when 是 Kotlin 中的"超级 switch":它不仅能替代 if-else 和 Java 的 switch,还能返回值、匹配任意条件、甚至当表达式用!

它是 Kotlin 最常用、最优雅的控制流工具之一。


二、基础用法:替代 if-else 和 switch

✅ 1. 基本匹配(类似 switch)
复制代码
val grade = "A"

when (grade) {
    "A" -> println("优秀")
    "B" -> println("良好")
    "C" -> println("及格")
    else -> println("不及格")
}

🔔 注意:不需要 break!Kotlin 自动"穿透"问题。

✅ 2. 多个值合并
复制代码
when (x) {
    1, 2, 3 -> println("小数字")
    4, 5 -> println("中等数字")
    else -> println("其他")
}
✅ 3. 区间匹配(超实用!)
复制代码
val score = 85

when (score) {
    in 90..100 -> "A"
    in 80..89 -> "B"
    in 70..79 -> "C"
    else -> "D"
}
✅ 4. 类型检查(Android 高频!)
复制代码
when (view) {
    is TextView -> view.text = "Hello"
    is ImageView -> view.setImageResource(R.drawable.icon)
    is Button -> view.isEnabled = true
    else -> Log.w("UnknownView", view::class.java.simpleName)
}

✅ 自动类型智能转换(smart cast):is TextView 后,view 直接就是 TextView 类型!


三、when 是表达式!可以返回值 💡

这是 Kotlin when 最强大的特性之一:

复制代码
val result = when (status) {
    LOADING -> "加载中..."
    SUCCESS -> "成功!"
    ERROR -> "出错了"
    else -> "未知状态"
}

// 直接用于 UI
textView.text = when (user.role) {
    "admin" -> "管理员"
    "user" -> "普通用户"
    else -> "访客"
}

✅ 每个分支必须有值(或抛异常),否则编译报错!


四、高级用法:任意条件匹配(不限于等值)

when 的每个分支可以是任意布尔表达式!

复制代码
val age = 25

val category = when {
    age < 13 -> "儿童"
    age < 18 -> "青少年"
    age < 60 -> "成年人"
    else -> "老年人"
}

🔥 这相当于 if-else if-else,但更清晰!

Android 实战:权限检查
复制代码
val message = when {
    ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED ->
        "相机已授权"
    shouldShowRequestPermissionRationale(Manifest.permission.CAMERA) ->
        "请允许相机权限以使用扫码功能"
    else ->
        "需要相机权限,请在设置中开启"
}
showDialog(message)

五、配合密封类(Sealed Class)------ Android 状态管理黄金组合!

这是现代 Android 开发(尤其 Jetpack Compose)中最推荐的模式:

复制代码
sealed class UiState {
    object Loading : UiState()
    data class Success(val data: List<Item>) : UiState()
    data class Error(val msg: String) : UiState()
}

// 在 Compose 中
@Composable
fun MyScreen(viewModel: MyViewModel) {
    val uiState by viewModel.uiState.collectAsState()

    when (uiState) {
        is UiState.Loading -> CircularProgressIndicator()
        is UiState.Success -> LazyColumn {
            items(uiState.data) { item -> ItemCard(item) }
        }
        is UiState.Error -> ErrorMessage(uiState.msg)
    }
}

✅ 优势:

  • 编译器检查全覆盖:如果你加了新状态,不处理就报错!
  • 类型安全 :is Success 后自动解构出 data
  • 代码清晰:状态 → UI 一一对应

六、常见陷阱 & 最佳实践

❌ 陷阱1:忘记 else(当 when 用作表达式时)
复制代码
val msg = when (status) {
    LOADING -> "加载中"
    SUCCESS -> "成功"
    // ❌ 编译错误!缺少 else 或 ERROR 分支
}

✅ 解决:确保所有可能值都被覆盖,或加 else。

❌ 陷阱2:在 when 中做复杂逻辑(降低可读性)
复制代码
when (user) {
    is Admin -> {
        // 20 行代码...
    }
    is Guest -> {
        // 15 行代码...
    }
}

✅ 建议:提取成函数

复制代码
when (user) {
    is Admin -> handleAdmin(user)
    is Guest -> handleGuest()
}
✅ 最佳实践1:优先用 when 替代长 if-else
复制代码
// 不好
if (type == "image") { ... }
else if (type == "video") { ... }
else if (type == "text") { ... }

// 好
when (type) {
    "image" -> ...
    "video" -> ...
    "text" -> ...
}
✅ 最佳实践2:结合 let 处理 nullable
复制代码
when (val user = fetchUser()) {
    null -> showLogin()
    else -> showProfile(user) // user 自动非空
}

七、对比 Java 的 switch

特性 Java switch Kotlin when
支持字符串 ✅(Java 7+) ✅
支持对象 ❌ ✅(通过 equals)
支持区间 ❌ ✅(in 1..10)
支持类型检查 ❌ ✅(is String)
支持任意表达式 ❌ ✅(when { x > 0 -> ... })
返回值 ❌ ✅(表达式!)
自动 break ❌(需手动) ✅(无穿透)

📌 Kotlin 的 when 完全碾压 Java 的 switch!


八、总结一句话

when 是 Kotlin 中集"模式匹配 + 表达式返回 + 类型智能转换"于一体的控制流神器,配合密封类,能写出安全、简洁、可维护性极高的 Android 代码。

从状态管理到权限处理,从 UI 渲染到数据转换 ------ when 无处不在。


💡 小练习:用 when 重构这段代码

复制代码
if (errorCode == 404) {
    message = "页面不存在"
} else if (errorCode == 500) {
    message = "服务器错误"
} else if (errorCode in 400..499) {
    message = "请求错误"
} else {
    message = "未知错误"
}

✅ 重构后:

复制代码
val message = when (errorCode) {
    404 -> "页面不存在"
    500 -> "服务器错误"
    in 400..499 -> "请求错误"
    else -> "未知错误"
}

是不是更清爽?😊

相关推荐
weixin_460443563 小时前
2026年新修订《网络安全法》实施:Java私有化考试系统如何做好SBOM、漏洞治理与安全升级?
java·开发语言·在线考试系统·企业培训考试系统·宏远培训考试系统·国企培训考试系统·国产化培训系统
Cc.Y6 小时前
Java零基础入门:可变字符串与包装类:StringBuilder、StringBuffer 与 通讯录管理系统实战
java·开发语言·python
阿森_dev6 小时前
2027 届毕设选题怎么选:30 个 Java 方向选题的实现难度排序
java·开发语言·spring boot·毕业设计·课程设计
by209996 小时前
C++ 多态:同一个基类接口,调用不同的函数
开发语言·c++·经验分享·多态
笔墨登场说说7 小时前
flink bin/start-cluster.sh 帮我做成开机启动
开发语言·python
Sarvartha7 小时前
Lambda 表达式和函数式接口
java·开发语言
小白学大数据7 小时前
拼多多反爬对抗实战:Scrapy 中间件化采集架构解析
开发语言·scrapy·中间件·架构
大圣编蚕7 小时前
初探 NDK 的世界:从零开始理解 Android 原生开发
android
云贝贝贝7 小时前
MySQL 慢查询定位与索引优化实战
android
学逆向的7 小时前
win32注入代码
开发语言·网络安全·api·win32