Kotlin 中的 ?. 和 . 语法详解

Kotlin 中的 ?.. 语法详解

一句话总结

语法 名称 作用
. 成员访问操作符 直接访问对象的属性或方法
?. 安全调用操作符 对象不为 null 时才访问,为 null 则返回 null

1. . 成员访问操作符(普通调用)

这是最基础的语法,和 Java、Python 等语言一样,用来访问对象的属性和方法

kotlin 复制代码
val name: String = "Kotlin"

// 用 . 访问属性
println(name.length)       // 6

// 用 . 调用方法
println(name.uppercase())  // KOTLIN

但是,如果对象可能为 null:

kotlin 复制代码
val name: String? = null   // 可空类型

// name.length   // ❌ 编译错误!可空类型不能直接用 . 调用

编译器会直接报错,不让你编译通过 ,因为如果 namenull,调用 .length 就会空指针崩溃。


2. ?. 安全调用操作符(Safe Call)

?. 就是为了解决上面的问题而设计的,它的逻辑很简单:

如果对象不为 null → 正常调用;如果为 null → 直接返回 null,不崩溃

kotlin 复制代码
val name: String? = null

val length: Int? = name?.length
// name 是 null → 不调用 .length → 直接返回 null
println(length)  // null(没有崩溃!)
kotlin 复制代码
val name: String? = "Kotlin"

val length: Int? = name?.length
// name 不是 null → 正常调用 .length
println(length)  // 6

3. 直观对比

kotlin 复制代码
val user: User? = null

// ❌ 用 . ------ 编译器直接报错,不让你这样写
// user.name

// ✅ 用 ?. ------ 安全,返回 null
user?.name   // 结果是 null

// ✅ 用 . ------ 但前提是类型不可空
val user2: User = User("Alice")
user2.name   // 结果是 "Alice"

你可以把 ?. 理解为一个简写:

kotlin 复制代码
// 这两种写法完全等价:

// 写法1:用 ?.
val result = user?.name

// 写法2:手动判断 null
val result = if (user != null) {
    user.name
} else {
    null
}

4. ?. 链式调用

?. 最强大的地方是可以链式使用,任何一环为 null 就直接短路返回 null:

kotlin 复制代码
class Address(val city: String?)
class Company(val address: Address?)
class User(val company: Company?)

val user: User? = User(Company(Address("北京")))

// 链式安全调用
val city: String? = user?.company?.address?.city
println(city)  // 北京

// 任何一环为 null,整个结果就是 null
val user2: User? = User(Company(null))
val city2: String? = user2?.company?.address?.city
println(city2)  // null(address 是 null,后面就不再调用了)

如果不用 ?.,你需要写大量嵌套判断:

kotlin 复制代码
// 不用 ?.(又丑又长)
val city = if (user != null) {
    if (user.company != null) {
        if (user.company.address != null) {
            user.company.address.city
        } else null
    } else null
} else null

5. 常见搭配

搭配 ?: (Elvis 操作符)------ 给个默认值

kotlin 复制代码
val name: String? = null

// 如果 name 为 null,就用 "未知" 代替
val displayName = name ?: "未知"
println(displayName)  // 未知

// 组合使用
val length = name?.length ?: 0
println(length)  // 0

搭配 ?.let ------ 不为 null 时执行代码块

kotlin 复制代码
val email: String? = "hello@kotlin.org"

email?.let {
    println("发送邮件到: $it")  // 只有 email 不为 null 才执行
}

6. 总结图示

复制代码
对象.属性          ← 普通调用,对象必须非空
对象?.属性         ← 安全调用,对象可空

                    ┌─ 不为 null → 正常调用,返回结果
  对象?.属性  ─────┤
                    └─ 为 null   → 跳过调用,返回 null

一句话记忆:

. 是"我确定它不是 null,直接访问"
?. 是"它可能是 null,帮我安全地试一下"

后记

2026年5月18日于上海,在claude opus 4.6辅助下完成。

相关推荐
优橙教育15 分钟前
5G网优培训 vs Java开发:转行选哪个?
java·开发语言·5g
想会飞的蒲公英1 小时前
计算机怎样读取中文文本:编码、清洗与标准化
人工智能·python·自然语言处理
SeaTunnel2 小时前
从 Python Script 地狱到标准化数据集成框架
大数据·开发语言·python·程序员·代码·seatunnel
深度研习笔记2 小时前
OpenCV工业视觉实战09|项目EXE打包+工控机无环境部署+后台常驻运行,彻底脱离Python环境,完成项目最终交付
python·opencv·webpack
碎光拾影2 小时前
ARM交叉工具链各工具作用及IMX6ULL平台LED+蜂鸣器裸机程序实现
java·开发语言·数据库
CCPC不拿奖不改名3 小时前
大模型推理架构与开源生态知识整理
数据库·windows·python·架构·langchain·开源·github
Marst Code3 小时前
(python)2026Plotly 库评估:交互式可视化到底值不值得引入?
开发语言·python
databook3 小时前
当散点图不够用时:用 t-SNE 可视化多维数据
python·数据分析·数据可视化
Miao121313 小时前
微服务 API 测试实践:海外某民宿平台如何构建模式驱动测试基础设施
java·开发语言
CRMEB系统商城4 小时前
开源自建还是SaaS订阅?算一笔3年经济账
java·大数据·开发语言·开源