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)
}

StringString? 是不同类型:

类型 是否允许为 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,返回长度;如果 namenull,结果就是 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 天练习

  1. 定义一个 String? 类型变量,分别赋值为 null"Kotlin",观察 ?.length 的输出。
  2. 写一个 printNameLength(name: String?) 函数,安全打印名字长度。
  3. 定义 UserAddress,用 ?. 安全获取城市名。

参考答案:

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 函数。
  • 如果 namenull,返回「匿名用户」。
  • 否则返回 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)

阶段复盘问题

  1. StringString? 有什么区别?
  2. ?. 的作用是什么?
  3. ?: 的作用是什么?
  4. 为什么不建议频繁使用 !!
  5. 什么是智能类型转换?
posted @ 2026-06-30 10:55  呢哇哦比较  阅读(8)  评论(0)    收藏  举报