空安全
Nullable、?.、!!、Elvis。
30 分钟
空安全
空安全是 Kotlin 的标志性特性:类型系统区分可空与不可空,?.、?:、!! 与 let 让 NPE 在编译期尽可能暴露。
学习目标
- 理解
String与String?的区别 - 掌握安全调用
?.、Elvis?:、非空断言!! - 会用
let、also处理可空链式逻辑
Nullable 类型
fun printLength(s: String) {
println(s.length) // s 不可空,无需判空
}
fun printLengthOrNull(s: String?) {
if (s != null) {
println(s.length) // 智能转换为 String
} else {
println("null")
}
}
fun main() {
printLength("hello")
printLengthOrNull(null)
printLengthOrNull("kotlin")
}
String? 表示可能为 null;String 编译器保证非空,赋值 null 会报错。
安全调用与 Elvis
data class Lesson(val slug: String, val title: String?, val order: Int)
fun getTitle(lesson: Lesson?): String {
return lesson?.title ?: "未命名"
}
fun main() {
val l1 = Lesson("kt-intro", "Kotlin 是什么", 1)
val l2 = Lesson("kt-draft", null, 2)
println(getTitle(l1)) // Kotlin 是什么
println(getTitle(l2)) // 未命名
println(getTitle(null)) // 未命名
// 链式安全调用
val len = l2.title?.length ?: 0
println("标题长度: $len")
}
?. 左侧为 null 则整个表达式为 null;?: 左侧为 null 时取右侧默认值。
let 与非空断言
fun processSlug(slug: String?) {
slug?.let { s ->
println("处理: ${s.uppercase()}")
} ?: println("slug 为空,跳过")
}
fun riskyParse(input: String?): Int {
// !! 非空断言:确定非空时用,否则 NPE
return input!!.toInt()
}
fun main() {
processSlug("kt-intro")
processSlug(null)
// 安全转换
val any: Any = "42"
val num = any as? Int // 失败返回 null,不抛异常
println(num) // null
}
let 仅在非空时执行块;!! 慎用,优先 ?. 与 ?:。
与 Java 对照
| Kotlin | Java |
|---|---|
String? | @Nullable String |
s?.length | s != null ? s.length() : null |