我是音葵
FOX4
平时我的任务很简单。
确认目标
分析环境
执行任务
不过今天的目标稍微有点特殊。
不是敌人。
也不是任务区域。
而是——
Kotlin
如果你还把 Kotlin 理解成“Android 上比较好用的 Java 替代品”,那么这份情报已经有点过时了。
现在是 2026 年
目前 Kotlin 的稳定版本已经来到 2.4.20。Kotlin 的发展重点,也早就不只是在 Android 上继续优化语法,而是在向多平台、现代工具链、WebAssembly,以及 AI 辅助开发等方向继续扩展。
所以这次,我想从自己的角度,重新整理一下:
现在的 Kotlin,到底是什么?
一、首先,Kotlin 到底是什么?
如果一定要用一句话说明:
Kotlin 是一门现代、静态类型的编程语言,并且正在发展成为覆盖 JVM、Android、iOS、桌面、服务器、JavaScript 和 WebAssembly 等环境的多平台语言生态。
以前大家想到 Kotlin,通常是:
Kotlin
↓
Android
这个印象并没有错。
Android 依然是 Kotlin 最重要的应用领域之一。
但现在已经不能只这样理解。
Kotlin 的战场正在逐渐变成:
Kotlin
│
┌─────────┼─────────┐
↓ ↓ ↓
Android Server Desktop
│ │ │
Compose JVM/Jakarta Compose
│
└──────┐
↓
Kotlin Multiplatform
/ | \
Android iOS Desktop
\
Web / Wasm
Kotlin 官方 2026 年的报告显示,全球已有约 810 万有 Kotlin 使用经验的开发者;超过一半的 Kotlin 开发者将它用于后端任务,超过三成参与 Multiplatform 项目。官方也明确把后端、多平台和 AI 视为 Kotlin 当前增长的重要方向。
所以……
如果以前的 Kotlin 像是一支主要负责 Android 任务的小队。
现在,它正在扩大自己的任务范围。
二、为什么我会喜欢 Kotlin?
我第一次认真看 Kotlin 的时候,最先注意到的并不是它有多少功能。
而是:
它很干净
例如:
val name = "Otogi"
就这样。
已经足够了。
当然,如果你希望明确写出类型,也可以:
val name: String = "Otogi"
但很多时候,编译器已经知道:
name
↓
String
那就没有必要重复说明。
这和执行任务其实很像。
如果情报已经确认:
目标:FOX4
我没有必要再写一份:
目标类型:人物
目标名称:FOX4
目标是否存在:是
……
很浪费时间。
Kotlin 的很多设计都体现了类似的思路:
如果编译器能够可靠地判断,就不要让开发者重复表达。
这也是我认为 Kotlin 很舒服的地方。
三、val 和 var:不是所有东西都需要变化
Kotlin 有两个非常基础的变量关键字:
val
var
例如:
val mission = "FOX Operation"
var ammo = 10
val 表示变量不能重新赋值。
var 则允许重新赋值。
所以:
val mission = "FOX Operation"
任务确定之后,就不要随便改变。
而:
var ammo = 10
ammo = 9
弹药数量当然可以随着任务推进发生变化。
这看起来只是一个小小的语法区别。
实际上,它涉及一个非常重要的工程原则:
减少不必要的可变状态。
如果一个变量可以不改变,那么就让它保持不变。
所以我的习惯是:
默认 val
必要时才 var
状态越少变化,程序就越容易理解。
任务也一样。
能固定的东西,就不要让它到处乱跑。
四、空安全:先确认目标,再执行操作
如果你以前写过 Java,大概见过这个:
NullPointerException
简称:
NPE
嗯……
我不喜欢它。
Kotlin 对这个问题的处理方式很直接。
例如:
val target: String? = null
注意这里的:
?
它表示:
target可能为空。
所以你不能直接:
println(target.length)
Kotlin 会阻止你。
你需要明确地写:
println(target?.length)
意思就是:
目标存在?
│
├── 是 → 获取 length
│
└── 否 → 返回 null
这其实非常合理。
如果连目标是否存在都没有确认,就直接开始执行下一步……
很危险
所以 Kotlin 干脆让类型系统帮你提前检查。
五、?::准备备用方案
有时候,目标不存在并不意味着任务必须终止。
例如:
val targetName = target ?: "Unknown"
如果 target 有值:
使用 target
如果没有:
使用 Unknown
这个:
?:
叫做 Elvis Operator。
名字有点奇怪。
不过很好用。
例如:
val nickname = profile?.nickname ?: "Anonymous"
意思就是:
profile 存在
↓
使用 nickname
profile 不存在
↓
使用 Anonymous
我喜欢这种写法。
因为它明确告诉程序:
正常情况是什么,备用方案又是什么。
不要把希望寄托在“应该不会发生异常”上。
真正可靠的系统,应该提前考虑异常情况。
六、data class:数据就应该只是数据
假设我要记录一个任务:
data class Mission(
val id: Int,
val target: String,
val priority: Int
)
然后:
val mission = Mission(
id = 4,
target = "Unknown",
priority = 10
)
如果任务优先级发生变化:
val emergencyMission = mission.copy(
priority = 100
)
这样就可以得到一个新的对象。
原来的 mission 不需要被修改。
这对于现代应用开发非常重要。
尤其是:
State
↓
UI
这样的架构。
状态发生变化。
产生新的状态。
UI 根据新的状态进行更新。
而不是整个程序到处修改同一个对象。
七、Lambda:把“怎么做”交出去
Kotlin 的 Lambda 也是我很喜欢的功能。
例如现在有几个目标:
val targets = listOf(
"Target-A",
"Target-B",
"Target-C"
)
我要筛选:
val selected = targets.filter {
it.startsWith("Target")
}
我要转换:
val names = targets.map {
"FOX-$it"
}
我要遍历:
targets.forEach {
println(it)
}
这里的:
it
就是 Lambda 的默认参数。
所以:
targets.filter {
it.startsWith("Target")
}
实际上就是:
“把所有目标交给我,我留下符合条件的。”
代码看起来几乎就是自然语言。
这就是 Lambda 很重要的地方:
把行为本身作为参数传递。
八、协程:等待,并不意味着什么都不做
接下来是现代 Kotlin 非常重要的一部分。
Coroutine
协程
假设我要从服务器获取任务:
suspend fun loadMission(): Mission {
return api.getMission()
}
然后:
launch {
val mission = loadMission()
showMission(mission)
}
这里的:
suspend
非常重要
它表示这个函数可以在协程中挂起。
比如服务器还没有返回结果。
程序可以在挂起点暂停当前协程,而不是必须一直阻塞线程等待。
但有一点需要特别注意:
suspend不等于自动创建线程,也不等于自动并发。
真正决定协程在哪里执行的,还包括:
CoroutineContext
Dispatcher
Scope
等等。
所以不要把:
suspend
理解成:
“这个函数自动跑到后台线程。”
不是这样的。
它更准确的含义是:
这个函数可以参与 Kotlin 的挂起式异步控制流。
如果用我的方式理解:
等待情报的时候,不代表必须一直站着占用资源。
等情报回来。
继续执行
九、Flow:持续接收情报
如果说:
suspend
更像:
“执行一次任务”
那么:
Flow
更像:
“持续接收情报”
例如一个 Repository 可以提供:
fun observeMission(): Flow<Mission> {
return missionRepository.observeMission()
}
然后上层:
missionFlow.collect { mission ->
println(mission)
}
Flow 可以用来表达持续变化的数据:
数据库变化
网络状态
用户输入
搜索结果
UI State
事件流
一个常见的现代 Android 数据流可能是:
Repository
↓
Flow
↓
ViewModel
↓
State
↓
Compose
这样看起来就很清楚。
数据从底层产生。
向上流动。
状态发生变化。
UI 响应变化。
这就是我理解的:
让情报沿着明确的路线流动。
十、Compose:不要告诉 UI“怎么改”,告诉它“应该是什么”
现在做 Android,如果还只按照传统 View 的思维来理解 UI,会越来越吃力。
现代 Android 开发的重要方向之一,就是:
Jetpack Compose
传统 UI 思路更像:
找到 View
↓
修改文字
↓
修改颜色
↓
修改 Visibility
↓
修改布局
Compose 则更接近:
@Composable
fun MissionScreen(
mission: Mission
) {
Column {
Text("Target: ${mission.target}")
Text("Priority: ${mission.priority}")
}
}
我只需要描述:
当前状态下,界面应该是什么样。
当:
Mission
发生变化。
Compose 根据新的状态重新组合 UI。
所以思维方式从:
“我要怎么修改 UI?”
变成:
“现在这个状态下,UI 应该是什么?”
这其实是一种非常重要的变化。
十一、K2:2026 年不能绕开的关键词
如果你还停留在 Kotlin 1.x 时代的印象里,那么有一件事情需要更新。
K2
K2 是 Kotlin 新一代编译器架构。
现代 Kotlin 2.x 的很多语言能力、编译器能力以及工具链,都建立在 K2 的基础上。
Compose Multiplatform 也已经完成向 K2 编译器的迁移。
所以现在学习 Kotlin,不应该只关注:
语法有没有变化?
还应该关注:
编译器
IDE
Build Tool
插件
多平台工具链
这些东西其实决定了:
代码从“写出来”到“真正构建、测试、发布”的整个过程。
而 Kotlin 2.4.20 也继续在标准库、Kotlin/Native、Kotlin/Wasm、Kotlin/JS、Gradle 和编译器工具等方面进行更新。
十二、Kotlin Multiplatform:真正需要共享的东西,才共享
然后是我认为 2026 年非常值得关注的方向:
Kotlin Multiplatform,简称 KMP。
它的核心思想并不是:
“所有平台必须使用完全一样的代码。”
而是:
让开发者决定哪些代码应该共享
例如:
Shared Kotlin
│
┌───────┼───────┐
↓ ↓ ↓
Android iOS Desktop
适合共享的内容可以包括:
业务逻辑
数据模型
网络层
数据库
状态管理
而平台特有的内容:
Android API
iOS API
平台 UI
特殊硬件
平台服务
仍然可以保持独立。
所以我一直觉得:
KMP ≠ 100% 代码复用
更准确的是:
KMP =
合理共享
+
保留平台差异
Kotlin Multiplatform 本身已经是 Stable;官方当前支持状态中,Android、iOS、Desktop JVM 和 Server JVM 均为 Stable,而 Kotlin/Wasm Web 目前仍为 Beta。
这意味着:
KMP 已经不是“以后可能会有用”的实验技术
它已经可以进入真实生产项目。
十三、Compose Multiplatform:UI 也可以共享
如果 KMP 负责共享业务逻辑,那么 Compose Multiplatform 则进一步让 UI 共享成为可能。
例如:
@Composable
fun MissionPanel(
mission: Mission
) {
Column {
Text("MISSION")
Text(mission.target)
Text("Priority: ${mission.priority}")
}
}
同一套 Compose UI 思路,可以覆盖:
Android
iOS
Desktop
而 Web 方向则通过 Kotlin/Wasm 继续发展。
目前 Compose Multiplatform 在 Android、iOS 和 Desktop 上已经 Stable,Web/Wasm 仍然是 Beta。
所以如果现在有人告诉你:
“Compose Multiplatform 已经完全覆盖所有平台,而且所有地方都一样成熟”
……
情报不准确。
确认目标之后再行动
这是基本原则。
不同平台仍然会存在平台特有 API 和行为差异。官方文档也明确说明,有些平台 API 仍然需要放在平台特定代码中实现。
十四、Kotlin/Wasm:Kotlin 正在接近 Web 的另一条路线
还有一个值得观察的方向:
Kotlin/Wasm
它可以把 Kotlin 编译成 WebAssembly。
例如:
Kotlin
↓
Kotlin/Wasm
↓
WebAssembly
↓
Browser
配合 Compose Multiplatform,就可以让 Kotlin/Compose UI 进入 Web 环境。
而且现在已经可以直接创建 Kotlin/Wasm + Compose Multiplatform 的 Web 应用。
不过这里也要保持冷静。
目前 Kotlin/Wasm 仍然处于 Beta
所以我不会说:
“Web 已经是 Kotlin 的成熟主战场。”
更准确的说法是:
这是一个正在快速成熟、值得关注的方向。
对我来说,Beta 的意思就是:
可以侦察。
可以测试。
可以建立原型。
生产环境则要根据项目风险谨慎判断。
十五、2026 年,还有 AI
然后……
就是现在几乎所有开发者都无法绕开的话题。
AI
现在写代码已经越来越接近:
人类
↓
提出需求
↓
AI
↓
生成代码
↓
人类审查
↓
测试
↓
发布
所以现在学习 Kotlin,重点也在变化。
过去可能需要大量记忆:
API
语法
模板
代码写法
现在 AI 可以帮我们完成其中相当一部分。
但是有些东西,我不会交给 AI。
例如:
架构怎么设计?
状态应该放在哪里?
哪些代码应该共享?
哪里需要并发?
异常应该怎么处理?
这个抽象是不是过度了?
这个方案到底是不是正确的?
这些问题需要开发者自己判断。
所以我认为:
AI 会减少“写代码”的工作量,但不会自动减少“思考”的工作量。
甚至恰恰相反。
当生成代码变得越来越便宜之后:
判断代码是否值得存在,会越来越重要。
十六、AI 可以负责执行,但目标必须由我确认
如果一定要用任务来比喻……
AI 很像一个执行能力非常强的辅助单位。
你告诉它:
“把这个功能写出来。”
它可能很快就能给你一份代码。
但是:
“这个功能真的应该这样设计吗?”
这件事情还是需要有人负责。
所以我更愿意把 AI 放在这里:
人类
│
确认目标
│
↓
AI
│
生成 / 修改
│
↓
测试
│
↓
人类审查
而不是:
人类
↓
AI
↓
直接发布
……
那太危险了。
目标都还没确认,就扣扳机?
不行。
十七、如果现在开始学习 Kotlin,我会怎么做?
如果是现在,也就是 2026 年,我不会建议你从头到尾背一本 Kotlin 语法大全。
我的路线会是:
Kotlin 基础
↓
空安全
↓
类与接口
↓
集合
↓
Lambda
↓
扩展函数
↓
Coroutine
↓
Flow
↓
Compose
↓
现代 Android 架构
↓
Kotlin Multiplatform
↓
Compose Multiplatform
↓
Kotlin/Wasm
↓
AI 辅助开发
然后——
做一个真正的项目。
十八、比如,做一个 FOX Mission Console
如果让我自己练习,我大概会做一个:
FOX Mission Console。
名字已经确定。
架构可以是:
Mission UI
│
Compose
│
State / ViewModel
│
Flow / Coroutine
│
Repository
│
Shared Business
│
Kotlin Multiplatform
/ | \
/ | \
Android iOS Desktop
│
└── Web / Wasm
这个项目可以一次练习:
Kotlin
K2
Compose
Coroutine
Flow
State
网络请求
数据库
KMP
Compose Multiplatform
Wasm
AI 辅助开发
但最重要的不是技术栈列表。
而是:
你会真正遇到问题。
为什么状态没有更新?
为什么协程执行顺序和想象的不一样?
为什么 Flow 没有收到数据?
为什么共享代码反而让架构变复杂?
为什么这个平台必须写特殊实现?
为什么 AI 生成的代码看起来没问题,实际上却不合理?
这些问题,才是学习真正开始的地方。
十九、所以,2026 年还值得学 Kotlin 吗?
我的答案是:
值得
但不要只是为了:
“学会 Kotlin 语法”
如果目标只是:
会写变量
会写函数
会写 class
那么很快就会遇到瓶颈。
真正值得掌握的是 Kotlin 背后的思维:
空安全
不可变数据
函数式思维
结构化并发
响应式数据流
声明式 UI
模块化
跨平台架构
明确边界
AI 协作
这些思想并不只属于 Kotlin。
它们本身就是现代软件工程的一部分。
二十、最后
……
说了这么多。
如果一定要我总结 Kotlin,我会这样写:
少一点重复。
少一点状态。
少一点意外。
多一点明确。
多一点组合。
多一点自动化。
如果编译器能帮我检查。
就让编译器检查。
如果框架能帮我管理状态。
就交给框架。
如果 AI 能帮我生成重复代码。
就让 AI 去做。
但有一件事情不能省略。
确认目标
因为无论程序还是任务:
执行得再快,如果目标错了,也只是在更快地走向错误的结果。
所以我真正关心的,一直不是:
“这段代码能不能写出来?”
而是:
“这段代码应该存在吗?”
“它应该这样设计吗?”
“如果情况发生变化,它还能正常工作吗?”
这才是我理解的编程。
Kotlin 只是让我在完成这些事情的时候,少处理一些不必要的麻烦。
所以——
如果你准备开始学习 Kotlin。
不用想太多。
先写第一行代码。
fun main() {
println("Mission Start.")
}
然后开始你的任务吧。
任务确认
Kotlin 入门任务,完成
—— FOX4 / 音葵
《我是音葵,来聊聊 2026 年的 Kotlin》
https://otogi.cn/archives/kotlin_01
评论