Kotlin第三阶段学习内容详情
Kotlin 第三阶段学习内容详情:空安全
本阶段目标是理解 Kotlin 如何减少空指针异常,并熟练使用可空类型、安全调用、Elvis 操作符和非空断言。空安全是 Kotlin 最重要的语法特性之一,学扎实后会明显感觉代码更稳。
建议用时:2 天。
阶段目标
- 能区分非空类型和可空类型。
- 能使用
?.安全访问可空对象。 - 能使用
?:提供默认值。 - 理解
!!的风险。 - 能使用
if判断完成智能类型转换。 - 能写出更安全的字符串和对象处理代码。
第 1 天:可空类型与安全调用
1. 为什么需要空安全
很多程序错误都来自空值。例如,一个变量本来应该保存用户名,但实际值是 null,如果直接访问它的长度,就会出错。
Java 中常见的空指针异常,在 Kotlin 中会被语法提前约束。
2. 非空类型
默认情况下,Kotlin 变量不能赋值为 null。
fun main() {
val name: String = "Kotlin"
println(name.length)
}
下面这样会报错:
fun main() {
val name: String = null // 错误
}
3. 可空类型
如果一个变量允许为 null,需要在类型后面加 ?。
fun main() {
val name: String? = null
println(name)
}
String 和 String? 是不同类型:
| 类型 | 是否允许为 null |
|---|---|
String |
否 |
String? |
是 |
Int |
否 |
Int? |
是 |
4. 可空变量不能直接访问属性
错误写法:
fun main() {
val name: String? = null
println(name.length) // 错误
}
因为 name 可能是 null,直接访问 length 不安全。
5. 安全调用 ?.
使用 ?. 可以安全访问可空变量。
fun main() {
val name: String? = null
println(name?.length)
}
如果 name 不为 null,返回长度;如果 name 为 null,结果就是 null,程序不会崩溃。
再看一个非空的例子:
fun main() {
val name: String? = "Kotlin"
println(name?.length)
}
6. 链式安全调用
对象层级比较深时,可以连续使用 ?.。
data class Address(val city: String)
data class User(val name: String, val address: Address?)
fun main() {
val user = User("Alice", null)
val city = user.address?.city
println(city)
}
第 1 天练习
- 定义一个
String?类型变量,分别赋值为null和"Kotlin",观察?.length的输出。 - 写一个
printNameLength(name: String?)函数,安全打印名字长度。 - 定义
User和Address,用?.安全获取城市名。
参考答案:
data class Address(val city: String)
data class User(val name: String, val address: Address?)
fun printNameLength(name: String?) {
println("名字长度:${name?.length}")
}
fun main() {
printNameLength(null)
printNameLength("Kotlin")
val user = User("Alice", null)
println(user.address?.city)
}
第 2 天:默认值、非空断言与智能转换
1. Elvis 操作符 ?:
?: 用于在左边结果为 null 时提供默认值。
fun main() {
val name: String? = null
val displayName = name ?: "匿名用户"
println(displayName)
}
配合安全调用很常见:
fun main() {
val name: String? = null
val length = name?.length ?: 0
println(length)
}
含义是:如果 name?.length 有值,就使用这个值;否则使用 0。
2. 非空断言 !!
!! 表示你强行告诉编译器:这个值一定不是 null。
fun main() {
val name: String? = "Kotlin"
println(name!!.length)
}
如果实际为 null,程序会崩溃:
fun main() {
val name: String? = null
println(name!!.length) // 运行时报错
}
初学阶段记住一句话:能不用 !! 就不用。
3. 智能类型转换
如果先判断变量不为 null,Kotlin 会自动把它当作非空类型使用。
fun main() {
val name: String? = "Kotlin"
if (name != null) {
println(name.length)
}
}
在 if 代码块中,name 已经被智能转换为 String。
4. 可空参数
函数参数也可以是可空类型。
fun getDisplayName(name: String?): String {
return name ?: "匿名用户"
}
fun main() {
println(getDisplayName(null))
println(getDisplayName("Alice"))
}
5. 可空返回值
函数返回值也可以是可空类型。
fun findUserName(id: Int): String? {
return if (id == 1) "Alice" else null
}
fun main() {
val name = findUserName(2)
println(name ?: "用户不存在")
}
综合练习
练习 1:昵称展示
要求:
- 写一个
getDisplayName(name: String?): String函数。 - 如果
name为null,返回「匿名用户」。 - 否则返回
name。
fun getDisplayName(name: String?): String {
return name ?: "匿名用户"
}
fun main() {
println(getDisplayName(null))
println(getDisplayName("小明"))
}
练习 2:字符串长度统计
fun getLength(text: String?): Int {
return text?.length ?: 0
}
fun main() {
println(getLength(null))
println(getLength("Kotlin"))
}
练习 3:用户城市展示
data class Address(val city: String)
data class User(val name: String, val address: Address?)
fun getUserCity(user: User?): String {
return user?.address?.city ?: "城市未知"
}
fun main() {
val user1 = User("Alice", Address("杭州"))
val user2 = User("Bob", null)
println(getUserCity(user1))
println(getUserCity(user2))
println(getUserCity(null))
}
必须掌握清单
常见错误
1. 可空变量直接访问属性
val name: String? = null
println(name.length) // 错误
应改为:
println(name?.length)
2. 滥用 !!
val name: String? = null
println(name!!.length)
应优先写成:
println(name?.length ?: 0)
阶段复盘问题
String和String?有什么区别??.的作用是什么??:的作用是什么?- 为什么不建议频繁使用
!!? - 什么是智能类型转换?

浙公网安备 33010602011771号