避免 NullPointerExceptions
编写安全代码的模式。
避免 NullPointerExceptions 是 CoddyKit 上的免费 Android Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Android Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Android Academy 课程共包含 4 节课。
目标:不再出现 NPE
当代码使用了实际为 null 的内容时,就会发生 NullPointerException,也就是 NPE。Kotlin 的设计目标是让这类问题变得很少见。
本课将综合您学过的工具,并说明 NPE 仍可能出现的少数情况。
!! 运算符
非 null 断言 !! 会告诉编译器相信某个值不为 null。如果判断错误,它就会抛出 NPE。
它会取消安全保护,因此应尽量少用,并且只能在您确定值不为 null 时使用。
fun main() {
val name: String? = "Ada"
println(name!!.length) // works, name is not null
}!! 可能导致崩溃
如果值确实为 null,!! 会在那一行准确地抛出 NullPointerException。
这是重新引入 Kotlin 正在防止的问题的主要方式。如果安全调用或 Elvis 运算符可以满足需求,请避免使用 !!。
val name: String? = null
println(name!!.length)
// throws KotlinNullPointerException优先选择安全替代方案
几乎所有使用 !! 的地方都可以改写为 ?. 和 ?:。安全写法不会导致崩溃。
请比较下面有风险的写法和安全写法。
// Risky:
val len1 = name!!.length
// Safe:
val len2 = name?.length ?: 0尽早验证
在代码边界处处理 null,然后在内部使用非 null 值。使用 Elvis 运算符结合 return 或 throw,可以在一开始就拒绝缺失的输入。
完成检查后,该值会被智能转换为非 null 类型。
fun length(s: String?): Int {
val text = s ?: return 0
return text.length
}requireNotNull
当 null 确实表示程序错误时,requireNotNull 会抛出清晰的错误,并返回非 null 值。
它比 !! 描述性更强,因为您可以添加消息。
fun start(config: String?) {
val c = requireNotNull(config) { "config missing" }
println(c.length)
}来自 Java 的平台类型
来自 Java 的值具有未知的可空性,这类值称为平台类型。Kotlin 无法保证它们不为 null。
使用 Java 库时,请显式声明预期类型,并采取防御性方式处理 null。
// From Java: String maybe = obj.getName();
val name: String? = obj.name // be safe
println(name?.length ?: 0)lateinit 陷阱
lateinit var 允许您延迟初始化非 null 属性。但在赋值之前使用它会抛出异常。
只有在确定该值会在任何访问发生之前被设置时,才应使用 lateinit。
lateinit var config: String
fun read() {
println(config.length)
// crashes if config was never set
}用默认值代替 null
很多时候,您可以选择合理的默认值,从而完全避免可空性。空字符串或空列表通常比 null 更好。
可空类型越少,出现 NPE 的机会就越少。
fun main() {
val tags: List<String> = emptyList()
println(tags.size) // 0, never null
}安全的数据处理流程
此程序读取一个可选值,安全地转换它,并始终生成结果。不使用 !!,也不会崩溃。
这正是实际 Android 代码应采用的风格。
fun main() {
val input: String? = null
val result = input?.trim()?.uppercase() ?: "N/A"
println(result) // prints: N/A
}最佳实践
优先使用非 null 类型,在边界处使用 Elvis 运算符处理 null,并使用 ?.let 执行可选操作。只有在确定不可能为 null 的少数情况下,才使用 !!。
遵循这些习惯,NullPointerExceptions 就会成为过去的问题。
val safe = data?.value ?: default
data?.let { handle(it) }快速检查
测试您对避免 NullPointerExceptions 的理解。
回顾
Kotlin 中的 NPE 通常来自 !!、来自 Java 的平台类型,或尚未初始化的 lateinit 值。优先使用非 null 类型和安全运算符,可以避免这些问题。
使用 ?.、?:、?.let 以及 requireNotNull 等验证方式,让代码不再因错误而崩溃。现在,您已经完成了 Kotlin 空安全的核心内容。
用 AI 导师学习 Kotlin — 免费
在浏览器中编写并运行真实代码,获得全天候 AI 导师的即时帮助,并在网页或应用中继续学习。
- 课程
- 36
- 课程
- 152
常见问题解答
「避免 NullPointerExceptions」课时是免费的吗?
是的 — 「避免 NullPointerExceptions」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Android Academy 课程的其余内容,请升级到 CoddyKit PRO。 Android Academy 课程共包含 4 节课。
「避免 NullPointerExceptions」这节课中我会学到什么?
编写安全代码的模式。 你通过在浏览器中直接运行的动手代码来练习 Android Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Android Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Android Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。
「避免 NullPointerExceptions」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Android Academy 课中编写并运行代码吗?
能。每节 Android Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- 可空类型与非空类型
- 安全调用与 Elvis
- let、also 与作用域函数
- 避免 NullPointerExceptions