Kotlin 可空值
最后修改日期:2025 年 3 月 22 日
Kotlin 的类型系统驯服了空指针异常的野兽,将类型分为可空和不可空两种。本教程深入探讨如何使用安全调用、Elvis 运算符等方法来处理空值,通过实用、真实的例子,确保您的代码不会崩溃。
可空类型
默认情况下,Kotlin 将变量锁定为不可空值—添加一个 ?
即可将 null
作为一个选项解锁。这就像一个安全开关,当 null
可能会潜入时,您可以打开它。
fun main() { var username: String = "Alice" // Locked: no null allowed // username = null // Error: Null can't crash this party var email: String? = "bob@site.com" // Unlocked: null's welcome email = null // All good here println(email) // Output: null }
username
保持不可空,而 email
通过 ?
接受 null
。想想用户资料—电子邮件可能是可选的,但用户名是必需的。Kotlin 在编译时强制执行这种区分。
安全调用
安全调用运算符 (?.
) 绕过 null
,仅在对象存在时才获取属性或方法—否则,它会耸耸肩并返回 null
,不会发脾气。
fun main() { val bio: String? = null val charCount = bio?.length println(charCount) // Output: null }
bio?.length
检查可空的 bio,而不会冒崩溃的风险。想象一个社交媒体应用程序—一些用户会跳过 bio,而 ?.
保持应用程序的正常运行,返回 null
而不是崩溃。
Elvis 运算符
当可空值变为空时,Elvis 运算符 (?:
) 迅速出现,提供一个回退值,使您的代码保持在正轨上,并提供一个默认值。
fun main() { val nickname: String? = null val displayName = nickname ?: "Guest" println(displayName) // Output: Guest }
如果 nickname
为 null
,nickname ?: "Guest"
则选择 "Guest"。想象一个论坛—没有昵称的用户会得到一个友好的默认值,这要感谢 Elvis 的巧妙救援。
安全类型转换
安全类型转换运算符 (as?
) 尝试进行类型切换而无需戏剧性——如果失败,您将得到 null
而不是 ClassCastException
。
fun main() { val input: Any = "42" val count: Int? = input as? Int println(count) // Output: null }
input as? Int
尝试将字符串转换为整数,安全地转换为 null
。想想解析用户输入—数字可能会以文本形式到达,而 as?
使管道保持流畅运行而不会崩溃。
非空断言
非空断言 (!!
) 关闭了 null
的大门,将可空类型强制转换为非空类型—但如果 null
溜了进来,就会发生 NullPointerException
爆炸。
fun main() { val token: String? = null val length = token!!.length // Boom! NullPointerException println(length) // Never reached }
token!!.length
押注 token
不为 null
—在这里,它输得很惨。仅当您 100% 确定令牌存在时,才在身份验证系统中使用它;否则,它就是一颗定时炸弹。
可空集合
集合可以包含可空类型,而像 filterNotNull
这样的工具会清除 null
,只留下好的东西。
fun main() { val scores: List= listOf(95, null, 87, null, 91) val validScores = scores.filterNotNull() println(validScores) // Output: [95, 87, 91] }
filterNotNull
从 scores
中清除 null
。想象一个测验应用程序—一些答案可能未评分 (null),并且这会清理列表以进行最终统计,无需大惊小怪。
使用可空类型的 Let 函数
let
函数与可空类型一起使用,仅在值存在时运行一个代码块—将其视为一个保镖,只允许非空值进入俱乐部。
fun main() { val address: String? = "123 Main St" address?.let { println("Shipping to: $it") // Output: Shipping to: 123 Main St } val noAddress: String? = null noAddress?.let { println("Shipping to: $it") // No output } }
address?.let
仅处理非空地址。在电子商务结账中,这确保了仅在存在送货详细信息时才处理它们—安全且有选择性。
链式安全调用
安全调用可以链接,像专业人士一样导航嵌套的可空类型,如果任何链接中断,则返回 null
。
data class User(val profile: Profile?) data class Profile(val city: String?) fun main() { val user: User? = User(null) val cityLength = user?.profile?.city?.length println(cityLength) // Output: null }
user?.profile?.city?.length
深入挖掘多层,在第一个 null
处退出。在旅行应用程序中,仅当用户和个人资料存在时,才会获取城市名称的长度—安全而流畅。
使用多个回退的空合并
Elvis 运算符可以堆叠回退值,在紧急情况下选择第一个非空值,就像一个备用计划,还有一个备用计划。
fun main() { val primaryPhone: String? = null val backupPhone: String? = null val defaultPhone = "N/A" val contact = primaryPhone ?: backupPhone ?: defaultPhone println(contact) // Output: N/A }
primaryPhone ?: backupPhone ?: defaultPhone
寻找有效的电话,最终结果是 "N/A"。在联系人管理器中,这确保您始终有内容可以显示,无论数据有多么稀疏。
结合 Let 和 Elvis
混合使用 let
和 ?:
可以创建一个紧密的空值处理流程,处理非空值,并为其他值提供回退。
fun main() { val coupon: String? = null val discount = coupon?.let { it.toInt() } ?: 0 println("Discount: $discount%") // Output: Discount: 0% }
如果存在,coupon?.let { it.toInt() } ?: 0
将优惠券代码转换为整数,否则默认为 0。在购物车中,这仅在代码有效时才应用折扣—干净且防崩溃。
处理可空值的最佳实践
- 依靠安全调用: 使用
?.
避免空值陷阱—当您可以滑行时,为什么还要冒崩溃的风险呢? - 设置智能默认值: 使用
?:
插入回退值,在数据不足时保持您的应用程序正常运行。 - 避免
!!
: 除非您绝对确定,否则要避开!!
—崩溃可不好玩。 - 释放
let
: 运用let
来把控空值,仅为 VIP(非空值)运行代码。
来源
本教程揭开了 Kotlin 空安全魔法的面纱,通过实用的角度展示了安全调用和 let
等工具。通过这些技巧,您将躲避空值灾难,并保持您的代码像岩石一样稳定。
作者
列出 所有 Kotlin 教程。