Kotlin 语法速览

1. 变量和常量

  • val:不可变变量(只读,类似 final)
  • var:可变变量
  • 类型推断:Kotlin 支持自动推断变量类型
1
2
3
4
5
6
7
8
fun main() {
val name = "Alice" // 不可变,类型推断为 String
var age = 25 // 可变,类型推断为 Int
// name = "Bob" // 错误:val 不能重新赋值
age = 26 // 正确:var 可以重新赋值

println("Name: $name, Age: $age")
}

2. 基本数据类型

  • 常见类型:Int, Double, String, Boolean, List, Map
  • 无基本类型与引用类型的区分,全部是对象
1
2
3
4
5
6
7
8
fun main() {
val integer: Int = 42
val double: Double = 3.14
val text: String = "Kotlin"
val isActive: Boolean = true

println("Int: $integer, Double: $double, String: $text, Boolean: $isActive")
}

3. 控制流:if 表达式

  • if 在 Kotlin 中是表达式,可以返回值
  • 替代三元运算符(Kotlin 无三元运算符)
1
2
3
4
5
6
7
8
9
10
11
fun main() {
val score = 85
val grade = if (score >= 90) {
"A"
} else if (score >= 80) {
"B"
} else {
"C"
}
println("Score: $score, Grade: $grade")
}

4. 控制流:when 表达式

  • 类似 switch,但更强大,支持多种条件
  • 也是表达式,可返回值
1
2
3
4
5
6
7
8
9
10
fun main() {
val day = 3
val dayName = when (day) {
1 -> "Monday"
2 -> "Tuesday"
3 -> "Wednesday"
else -> "Unknown"
}
println("Day $day is $dayName")
}

5. 循环

  • for:用于迭代集合或范围
  • whiledo-while:与 Java 类似
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
fun main() {
// for 循环
println("Numbers 1 to 5:")
for (i in 1..5) {
print("$i ")
}
println()

// while 循环
var count = 3
println("Counting down:")
while (count > 0) {
print("$count ")
count--
}
}

6. 函数

  • 使用 fun 关键字
  • 支持默认参数、命名参数、单表达式函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 带默认参数的函数
fun greet(name: String, greeting: String = "Hi"): String {
return "$greeting, $name!"
}

// 单表达式函数
fun sum(a: Int, b: Int) = a + b

// 高阶函数
fun apply(x: Int, op: (Int) -> Int) = op(x)
fun double(x: Int): Int = x * 2

fun main() {
// 调用函数
println(greet("Alice"))
println(greet("Bob", "Hello"))

println(sum(3, 5))

println(apply(5) { it * 2 }) // 10,等价于 apply(5, { it * 2 })
println(apply(5) { x: Int -> x * 2 }) // 完整形式
println(apply(5, ::double)) // 输出 10
}

7. 类和对象

  • 使用 class 定义类
  • 属性自动生成 getter/setter
  • 支持构造函数、主构造函数、初始化块
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class Person(val name: String) { // 主构造函数
private val secret = 42
protected val subclassVisible = "Protected"
internal val moduleVisible = "Internal"

var age: Int = 0
get() = field
set(value) {
if (value >= 0) field = value
}

init { // 初始化块
println("Person created: $name")
}

constructor(name: String, age: Int) : this(name) {
this.age = age
}

fun introduce() {
println("Hi, I'm $name, $age years old.")
}

fun getAgeAfterYears(years: Int): Int {
return age + years
}
}

fun main() {
val person = Person("Alice", 25)
person.introduce()
println("Age in 5 years: ${person.getAgeAfterYears(5)}")
}

8. 继承和接口

  • 默认类是 final,需用 open 允许继承
  • 接口使用 interface,实现用 :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
interface Animal {
fun makeSound()
}

open class Pet(val name: String) // 使用 val 或者 var 把 name 声明为属性

class Dog(name: String) : Pet(name), Animal { // 这里的 name 只是构造函数的参数,不是属性
override fun makeSound() {
println("$name says Woof!")
}
}

abstract class Shape {
abstract fun area(): Double
}

class Circle(val radius: Double) : Shape() {
override fun area() = Math.PI * radius * radius
}

fun main() {
val dog = Dog("Buddy")
dog.makeSound()
}

9. 空安全

  • 可空类型用 ? 表示
  • 安全调用 ?.,Elvis 运算符 ?:,非空断言 !!
1
2
3
4
5
6
7
8
9
10
11
fun main() {
val nullableString: String? = null
// 安全调用
println("Length: ${nullableString?.length}")
// Elvis 运算符
val length = nullableString?.length ?: 0
// val length = nullableString?.length ?: throw IllegalArgumentException("nullableString 不能为空")
println("Length with Elvis: $length")
// 非空断言(小心使用)
// val length2 = nullableString!!.length // 会抛出 NullPointerException
}

10. 集合

  • 支持 List, Set, Map
  • 提供不可变和可变集合:listOf, mutableListOf
1
2
3
4
5
6
7
8
9
10
fun main() {
val numbers = listOf(1, 2, 3, 4)
val mutableList = mutableListOf("apple", "banana")
val map = mapOf(1 to "one", 2 to "two")

println("Numbers: $numbers")
mutableList.add("orange")
println("Mutable List: $mutableList")
println("Map: $map")
}

11. Lambda 表达式和匿名函数

  • Lambda 语法:{ 参数 -> 表达式 }
  • 常用于集合操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
fun main() {
val numbers = listOf(1, 2, 3, 4, 5)
// Lambda 过滤
val evenNumbers = numbers.filter { it % 2 == 0 } // it 是 lambda 表达式的默认参数名,仅在 lambda 有一个参数时才可用
println("Even numbers: $evenNumbers")

// Lambda 映射
val squared = numbers.map { x -> x * x } // 手动制定参数名为 x,也可以写成 { it * it }
println("Squared: $squared")

// 多参数必须显式命名
val map = mapOf("a" to 1, "b" to 2)
map.forEach { key, value -> println("$key=$value") }

// 函数引用简写
val names = listOf("Tom", "Alice", "Bob")
names.forEach(::println) // ::println 等价于 { name -> println(name) }

// 匿名函数
val f1 = fun(x: Int): Int { return x + 1 }
val f2 = { x: Int -> x + 1 }
val f3 = { x: Int -> println(x + 1) }
val f4 : (Int) -> Unit = { x -> println(x + 1) }
}

12. 扩展函数

  • 为现有类添加方法,无需继承
1
2
3
4
5
6
7
8
9
10
11
12
13
// 扩展函数
fun String.reverse(): String {
return this.reversed()
}

fun String.addExclamation() = "$this!"

fun main() {
val text = "Kotlin"
println(text.reverse())

println("Hello".addExclamation()) // Hello!
}

13. 数据类

  • 使用 data class 自动生成 toString, equals, hashCode 等,主构造函数至少一个参数,不可被 open
1
2
3
4
5
6
7
8
data class User(val name: String, val age: Int)

fun main() {
val user1 = User("Alice", 25)
val user2 = User("Alice", 25)
println("User1: $user1")
println(user.copy(name = "Bob"))
}

14. 协程

  • 用于异步编程,需引入 kotlinx.coroutines
  • 使用 launchasync 启动协程
1
2
3
4
5
6
7
8
9
10
11
12
13
import kotlinx.coroutines.*

fun main() {
val suspendFunc: suspend () -> Unit = { println("Suspended") }
// 运行协程
runBlocking {
launch {
delay(1000)
println("Hello from coroutine!")
}
println("Main thread continues")
}
}

注意:协程示例需要添加 kotlinx-coroutines-core 依赖到项目中,否则无法运行。

概述

Kotlin 协程引入于 Kotlin 1.3,是一种基于线程的轻量级并发工具,适合处理异步任务,基于 kotlinx.coroutines 库。Kotlin 协程支持挂起(suspend)机制,可以挂起和恢复,允许以顺序风格编写异步代码,类似于同步代码,但不会阻塞线程,同时避免传统回调地狱。协程的核心优势包括资源高效(不阻塞线程)和结构化并发(确保资源管理)。每个协程必须在一个作用域(CoroutineScope)中启动。

协程语法点包括:

  1. 启动协程(如 launchasync
  2. 挂起函数
  3. 上下文和调度器(如 Dispatchers
  4. 取消和超时
  5. 异常处理
  6. 结构化并发(如 coroutineScope
  7. 通道(Channel
  8. 流(Flow
  9. 选择表达式(select
  10. 测试工具

协程实际应用场景包括网络请求、数据库操作、并发任务和超时处理。

语法总结

语法点 用途 示例场景
launch 启动无返回结果的协程 后台任务,如日志记录
async 启动返回结果的协程 并行计算结果
runBlocking 阻塞线程等待协程完成 测试或主函数入口
withContext 切换上下文运行挂起块 网络请求或 I/O 操作
suspend 函数 定义可挂起的异步函数 网络请求或 I/O 操作
Dispatchers 选择执行线程(如 IO、Main、Default) UI 更新或数据库操作
JobDeferred 管理任务生命周期和结果 等待任务完成或取消
取消和超时 取消协程或设置时间限制 超时网络请求
异常处理 处理协程中的异常 错误日志记录
coroutineScope 结构化并发管理子协程 确保任务顺序执行
supervisorScope 容错结构化并发 子任务失败不影响其他
Channel 协程间通信 生产者-消费者模式
Flow 处理异步数据流 实时数据更新,如传感器数据
select 选择第一个可用结果 多个异步操作竞争
yield 让出执行权 协作式多任务
joinAll 等待多个 Job 完成 批量任务同步
awaitAll 等待多个 Deferred 结果 并发结果收集
测试工具 测试协程行为 单元测试和集成测试

启动协程

14.1launch

启动不返回结果的协程。

1
2
3
4
5
6
7
8
9
import kotlinx.coroutines.*

fun main() = runBlocking {
launch {
delay(1000L)
println("World!")
}
println("Hello,")
}

14.2async

启动返回 Deferred<T> 的协程,用于获取结果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import kotlinx.coroutines.*

suspend fun fetchData1(): String = withContext(Dispatchers.IO) {
delay(1000L)
"Data1"
}

suspend fun fetchData2(): String = withContext(Dispatchers.IO) {
delay(1000L)
"Data2"
}

fun main() = runBlocking {
val deferred1 = async { fetchData1() }
val deferred2 = async { fetchData2() }
println("${deferred1.await()} and ${deferred2.await()}")
}

14.3runBlocking

阻塞当前线程直到协程完成,常用于测试或主函数。用于在 main函数中桥接阻塞与非阻塞代码。在作用域中启动的所有协程(如 launch {})必须完成,runBlocking才会返回。

1
2
3
4
5
6
7
8
9
10
11
12
import kotlinx.coroutines.*

fun main() {
runBlocking {
launch {
delay(1000)
println("inside launch")
}

println("Hello from runBlocking")
}
}

上面的代码中, runBlocking { ... } 会阻塞当前线程,在当前线程中创建一个顶层协程(CoroutineScope),println("Hello from runBlocking") 是在 runBlocking 的协程中执行的(运行在主线程,但属于协程代码)。

14.4withContext

在指定上下文运行挂起块,返回结果。

1
2
3
4
5
6
7
8
9
10
11
import kotlinx.coroutines.*

suspend fun fetchData(): String = withContext(Dispatchers.IO) {
delay(1000L)
"Data from network"
}

fun main() = runBlocking {
val data = fetchData()
println(data)
}

挂起函数

14.5 suspend

挂起函数用 suspend 关键字标记,只能从其他挂起函数或协程中调用,支持 delay 等挂起操作。

1
2
3
4
5
6
7
8
9
10
import kotlinx.coroutines.*

suspend fun doSomething() {
delay(1000L)
println("Done something")
}

fun main() = runBlocking {
doSomething()
}

协程作用域

14.6 Kotlin 协程作用域

## 协程作用域 是否结构化 是否阻塞线程 生命周期 典型用途 是否推荐
1 runBlocking ✅ 是 ✅ 是 直到 block 执行完毕 测试、main 函数入口 ✅(仅限测试/入口)
2 coroutineScope ✅ 是 ❌ 否 当前 suspend 函数结束 并发封装、函数内结构化并发 ✅ 推荐
3 supervisorScope ✅ 是 ❌ 否 当前 suspend 函数结束 容错并发(互不影响) ✅ 推荐
4 GlobalScope ❌ 否 ❌ 否 应用进程存活期间 后台任务(不推荐) ⚠️ 慎用(可能泄漏)
5 自定义 CoroutineScope(...) ✅/❌ 取决于 Job ❌ 否 由 Job 控制(手动 cancel) 封装类、组件内任务 ✅ 合理使用
7 actor / produce ✅ 是 ❌ 否 通道关闭或被取消 Channel 并发、消息队列 ✅ 特定场景推荐
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
import kotlinx.coroutines.*

fun main() = runBlocking {
println("🔷 1. runBlocking started on [${Thread.currentThread().name}]")

// 2. coroutineScope(结构化并发)
coroutineScope {
launch {
delay(100)
println("🔷 2. coroutineScope: child coroutine on [${Thread.currentThread().name}]")
}
}

// 3. supervisorScope(不会因子协程失败而取消整个作用域)
try {
supervisorScope {
launch {
delay(200)
println("🔷 3. supervisorScope: success task")
}
launch {
delay(100)
throw RuntimeException("🔷 3. supervisorScope: failed task")
}
}
} catch (e: Exception) {
println("🔴 Caught exception from supervisorScope: $e")
}

// 4. GlobalScope(不建议常用)
val job = GlobalScope.launch {
delay(300)
println("🔷 4. GlobalScope coroutine on [${Thread.currentThread().name}]")
}

// 等待 GlobalScope 启动的协程完成
// 如果不加这一行,上面的 GlobalScope 无法打印,因为 GlobalScope 启动的是一个全局线程,不是 runBlocking 的一部分,runBlocking 执行完就退出了,主线程结束,整个进程随之结束,导致 GlobalScope 中来不及打印就被强行终止了。
job.join()

// 5. 自定义 CoroutineScope
val customScope = CoroutineScope(Job() + Dispatchers.Default)
val customJob = customScope.launch {
println("🔷 5. Custom CoroutineScope running on [${Thread.currentThread().name}]")
}

// 6. produce 示例(生产者管道)
val numberProducer = produce {
repeat(3) {
delay(100)
send(it * it)
}
close()
}
for (num in numberProducer) {
println("🔷 6. produce: received $num")
}

// 7. actor 示例(带状态协程处理器)
val sumActor = actor<Int> {
var sum = 0
for (msg in channel) {
sum += msg
println("🔷 7. actor: received $msg, current sum = $sum")
}
}

listOf(1, 2, 3).forEach { sumActor.send(it) }
sumActor.close()

println("🕒 Waiting for GlobalScope & other coroutines...")
delay(1000) // 等待其他 coroutine 执行完成

// 记得手动 cancel 非结构化作用域
customJob.join()
customScope.cancel()
println("✅ runBlocking completed.")
}

14.7 Android 扩展作用域

## Android Scope 是否结构化 生命周期绑定对象 典型用途 是否推荐
1 viewModelScope ✅ 是 ViewModel 生命周期 网络/IO/业务逻辑 ✅ 推荐
2 lifecycleScope ✅ 是 Activity / Fragment 生命周期 启动任务 / UI操作 ✅ 推荐
3 repeatOnLifecycle ✅ 是 生命周期状态变化(如 STARTED) 生命周期感知、数据收集(Flow) ✅ 推荐

MainActivity.kt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.viewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch

class MainActivity : ComponentActivity() {

private val viewModel by viewModels<MyViewModel>()

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

// ✅ 1. lifecycleScope:跟随 Activity 生命周期
lifecycleScope.launch {
delay(300)
println("1️⃣ lifecycleScope → Thread: ${Thread.currentThread().name}")
}

// ✅ 2. repeatOnLifecycle:STARTED 时自动启动,STOPPED 时自动取消
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.timerFlow.collect {
println("2️⃣ repeatOnLifecycle collect: $it")
}
}
}

// ✅ 3. viewModelScope(定义在 ViewModel 中)
viewModel.loadData()
}
}

MyViewModel.kt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch

class MyViewModel : ViewModel() {

// Flow 模拟定时器
val timerFlow: Flow<Int> = flow {
var counter = 0
while (true) {
emit(counter++)
delay(1000)
}
}

fun loadData() {
viewModelScope.launch {
delay(500)
println("3️⃣ viewModelScope → Thread: ${Thread.currentThread().name}")
}
}
}

输出

1
2
3
4
5
6
1️⃣ lifecycleScope → Thread: main
3️⃣ viewModelScope → Thread: main
2️⃣ repeatOnLifecycle collect: 0
2️⃣ repeatOnLifecycle collect: 1
2️⃣ repeatOnLifecycle collect: 2
...

说明

  • lifecycleScope → 生命周期感知,自动取消协程(适合 UI 层数据加载等)

  • repeatOnLifecycle → 更细粒度的生命周期感知(可结合 Flow 实现 UI 活动期间自动收集)

  • viewModelScope → 随 ViewModel.onCleared() 自动取消,适合业务处理逻辑

使用场景

使用场景 推荐作用域
main 函数或测试 runBlocking
挂起函数内并发 coroutineScope
容错并发 supervisorScope
UI 层任务 viewModelScope / lifecycleScope
库或类封装内建 scope CoroutineScope(...)
Flow、通道数据源 produce / actor 内隐含作用域
后台不销毁任务 极少情况用 GlobalScope(通常不推荐)

14.8 协程上下文和调度器

调度器(如 Dispatchers.MainDispatchers.IODispatchers.DefaultDispatchers.Unconfined)决定协程运行的线程。

1
2
3
4
launch(Dispatchers.Main) { }      // UI线程
launch(Dispatchers.IO) { } // IO密集型
launch(Dispatchers.Default) { } // CPU密集型
launch(Dispatchers.Unconfined) { } // 不固定线程,惯性调度
1
2
3
4
5
6
7
import kotlinx.coroutines.*

fun main() = runBlocking {
launch(Dispatchers.IO) {
println("Running on IO thread: ${Thread.currentThread().name}")
}
}

Job 和 Deferred

14.9 Job

🔹 Job:表示一个可以被取消的协程任务

✅ 特点:

  • 代表一个正在运行的协程任务
  • 可以:
    • 取消(job.cancel()
    • 等待其完成(job.join()
  • 不返回结果值,只表示任务的生命周期

✅ 示例:

1
2
3
4
5
6
7
8
9
10
11
12
import kotlinx.coroutines.*

fun main() = runBlocking {
val job = launch {
delay(1000L)
println("Job completed")
}

println("Waiting for job...")
job.join() // 等待协程完成
println("Main function continues")
}

14.10 Deferred

🔹 Deferred<T>:表示一个带返回值的协程任务(类似于 Future<T>

✅ 特点:

  • Job 的子类型
  • 表示一个异步计算的结果
  • 使用 async 创建,调用 .await() 获取结果
  • 也可以取消、检查是否完成

✅ 示例:

1
2
3
4
5
6
7
8
9
10
11
12
import kotlinx.coroutines.*

fun main() = runBlocking {
val deferred: Deferred<Int> = async {
delay(1000L)
42
}

println("Doing other things...")
val result = deferred.await() // 等待并获取返回值
println("Result: $result")
}

🔍 JobDeferred 的对比

属性/行为 Job Deferred<T>
是否返回结果值 ❌ 无 ✅ 有返回值 (T)
创建方式 launch { ... } async { ... }
获取结果方式 await()
取消任务 .cancel() .cancel()
等待完成 .join() .await()
是否继承自 Job ✅ 本身就是 ✅ 是 Job 的子接口
典型用途 启动独立任务 启动异步计算并获取值

✅ 使用建议

场景 使用类型 说明
启动任务但不关心结果 launchJob 适合 UI 更新、日志、并发 fire-and-forget
启动异步任务并获取值 asyncDeferred<T> 比如网络请求、计算、数据处理等

💡 补充知识点:async 的懒启动模式

1
2
3
4
5
6
val deferred = async(start = CoroutineStart.LAZY) {
delay(1000)
100
}
// ... 之后需要时调用 await 会启动
val result = deferred.await()

取消和超时

14.11 cancel

取消:用 cancel 取消协程。

1
2
3
4
5
6
7
8
9
10
11
12
13
import kotlinx.coroutines.*

fun main() = runBlocking {
val job = launch {
repeat(5) { i ->
println("Coroutine executing $i")
delay(500L)
}
}
delay(1300L)
job.cancel()
println("Coroutine cancelled")
}

可响应取消的方式

1
2
3
4
5
suspend fun doWork() {
while (isActive) {
// 做一些任务
}
}

14.12 withTimeout

超时:用 withTimeout 设置时间限制。 抛出 TimeoutCancellationException

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import kotlinx.coroutines.*

fun main() = runBlocking {
try {
withTimeout(1300L) {
repeat(5) { i ->
println("Processing $i")
delay(500L)
}
}
} catch (e: TimeoutCancellationException) {
println("Timed out")
}
}

14.13 withTimeoutOrNull

返回 null,不抛异常 ✅

1
2
3
4
5
6
7
8
withTimeout(1000) {
delay(2000) // 抛出 TimeoutCancellationException
}

val result = withTimeoutOrNull(1000) {
delay(2000)
"This won't return"
} ?: "Timeout!"

14.14 异常处理

使用 CoroutineExceptionHandler 处理异常(launch中使用)。

1
2
3
4
5
6
7
8
9
10
11
12
import kotlinx.coroutines.*

fun main() = runBlocking {
// 在 Kotlin 中,_ 是一个 占位符变量名,表示“我不关心这个参数的值”。
val handler = CoroutineExceptionHandler { _, exception ->
println("Caught $exception")
}
launch(handler) {
throw Exception("Error in coroutine")
}
delay(1000L)
}

使用 try-catch 处理异常。

1
2
3
4
5
6
7
launch {
try {
throw Exception("Error")
} catch (e: Exception) {
println("Caught: $e")
}
}

协程组合与并发控制

14.15 并发执行任务 + 组合结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import kotlinx.coroutines.*

suspend fun getUser(): String {
delay(1000) // 模拟耗时任务
println("👤 getUser completed on [${Thread.currentThread().name}]")
return "User123"
}

suspend fun getPosts(): List<String> {
delay(800) // 模拟另一个耗时任务
println("📝 getPosts completed on [${Thread.currentThread().name}]")
return listOf("Post A", "Post B", "Post C")
}

fun main() = runBlocking {
println("🚀 Running in [${Thread.currentThread().name}]")

val userDeferred = async { getUser() }
val postsDeferred = async { getPosts() }

// to 是 Kotlin 中的一个非常常用的 中缀函数,用于创建键值对 (Pair)。
// val (a, b) 是解构(destructuring),用多个变量同时接收一个对象(Pair、Triple、map 或数据类)的多个字段值。
val (a, b) = userDeferred.await() to postsDeferred.await()
println("✅ Combined result: $a + $b")
}

14.16 顺序执行多个挂起函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import kotlinx.coroutines.*

suspend fun getUser(): String {
delay(1000)
println("👤 getUser completed on [${Thread.currentThread().name}]")
return "User456"
}

suspend fun getPosts(user: String): List<String> {
delay(800)
println("📝 getPosts for $user completed on [${Thread.currentThread().name}]")
return listOf("Post X", "Post Y")
}

fun main() = runBlocking {
println("🚀 Running in [${Thread.currentThread().name}]")

val user = getUser()
val posts = getPosts(user)

println("✅ Result for $user: $posts")
}

区别说明

模式 是否并发 用法 适合场景
async + await ✅ 是 并发获取多个独立结果 多个不依赖关系的网络/API 请求
顺序调用 ❌ 否 一个接一个 后一个依赖前一个结果

结构化并发

结构化并发的核心:

  • 父协程自动管理子协程
  • 作用域退出时取消未完成子协程
  • 错误自动传播

14.17 coroutineScope

coroutineScope: 创建作用域,等待所有子协程完成。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import kotlinx.coroutines.*

suspend fun performTasks() = coroutineScope {
launch {
delay(1000L)
println("Task 1")
}
launch {
delay(2000L)
println("Task 2")
}
}

fun main() = runBlocking {
performTasks()
println("All tasks completed")
}

14.18 supervisorScope

supervisorScope: 类似,但子协程失败不影响其他。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import kotlinx.coroutines.*

suspend fun performTasks() = supervisorScope {
launch {
delay(1000L)
throw Exception("Task 1 failed")
}
launch {
delay(2000L)
println("Task 2 completed")
}
}

fun main() = runBlocking {
try {
performTasks()
} catch (e: Exception) {
println("Caught exception: $e")
}
println("Main function continues")
}

14.19 通道(Channels)

用于协程间通信,支持生产者-消费者模式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.*

fun main() = runBlocking {
val channel = Channel<Int>()

launch {
for (x in 1..5) channel.send(x * x)
channel.close()
}

launch {
for (y in channel) {
println(y)
}
}

println()
}

14.20 流(Flows)

Flow(协程版响应式流) 的特性:

  • 是冷流(调用 collect 才执行)
  • 自动挂起支持
  • 支持背压、变换、合并等操作符(如 map、filter、combine)

处理异步数据流。

1
2
3
4
5
6
7
8
9
10
11
12
13
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*

fun main() = runBlocking {
flow {
for (i in 1..3) {
delay(100)
emit(i)
}
}.collect {
value -> println(value)
}
}

14.21 选择表达式(Select Expression)

同时等待多个挂起操作,选择第一个可用结果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import kotlinx.coroutines.*
import kotlinx.coroutines.selects.*

suspend fun selectExample1(scope: CoroutineScope): String {
return try {
val deferred1 = scope.async {
delay(1000L)
"Result 1"
}
val deferred2 = scope.async {
delay(500L)
"Result 2"
}

select<String> {
deferred1.onAwait { it }
deferred2.onAwait { it }
}
} catch (e: Exception) {
"Error occurred: ${e.message}"
}
}

suspend fun selectExample2(): String = coroutineScope {
// 表示从 coroutineScope block 中返回, 而不是返回外部函数,可省略
return@coroutineScope try {
val deferred1 = async {
delay(1000L)
"Result 1"
}
val deferred2 = async {
delay(500L)
"Result 2"
}

select<String> {
deferred1.onAwait { it }
deferred2.onAwait { it }
}
} catch (e: Exception) {
"Error occurred: ${e.message}"
}
}

fun main() {
runBlocking {
val result1 = selectExample1(this)
println(result1)
val result2 = selectExample2()
println(result2)
}
}

工具函数

14.23 yield

让出执行权,允许其他协程运行,适合协作式多任务。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import kotlinx.coroutines.*

fun main() = runBlocking {
launch {
repeat(5) {
println("Coroutine 1: $it")
yield()
}
}
launch {
repeat(5) {
println("Coroutine 2: $it")
yield()
}
}
}

输出:Coroutine 1Coroutine 2 交替执行。

14.24 joinAll

等待多个 Job 完成。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import kotlinx.coroutines.*

fun main() {
runBlocking {
val job1 = launch {
delay(1000L)
println("Job 1")
}

val job2 = launch {
delay(2000L)
println("Job 2")
}

joinAll(job1, job2)
println("All jobs completed")
}
}

输出:Job 1Job 2All jobs completed

14.25 awaitAll

等待多个 Deferred 完成,返回结果列表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import kotlinx.coroutines.*

fun main() {
runBlocking {
val deferred1 = async {
delay(1000L)
1
}

val deferred2 = async {
delay(2000L)
2
}

val results = awaitAll(deferred1, deferred2)
println(results)
}
}

输出:Results: [1, 2]

14.26 测试协程

使用 runBlockingTestTestCoroutineDispatcher 测试协程,适合单元测试。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package test

import kotlinx.coroutines.async
import kotlinx.coroutines.delay
import kotlinx.coroutines.test.advanceTimeBy
import kotlinx.coroutines.test.runTest
import org.junit.Assert
import kotlin.test.Test

class CoroutineTest {

@Test
fun testCoroutine() = runTest {
val deferred = async {
delay(1000L)
42
}

advanceTimeBy(1000L)
val result = deferred.await()
println("Result in test: $result")
Assert.assertEquals(42, result)
}
}

1
2
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.3")
testImplementation("junit:junit:4.13.2")

实际应用场景

14.27 网络请求(Android)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import kotlinx.coroutines.*
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.http.GET

interface ApiService {
@GET("data")
suspend fun getData(): String
}

class MainViewModel : ViewModel() {
private val retrofit = Retrofit.Builder()
.baseUrl("https://api.example.com/")
.addConverterFactory(GsonConverterFactory.create())
.build()
private val apiService = retrofit.create(ApiService::class.java)

fun fetchData() {
viewModelScope.launch {
try {
val data = apiService.getData()
println("Fetched data: $data")
} catch (e: Exception) {
println("Error: $e")
}
}
}
}

14.28 数据库操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import androidx.room.*
import kotlinx.coroutines.*

@Entity
data class User(@PrimaryKey val id: Int, val name: String)

@Dao
interface UserDao {
@Insert
suspend fun insert(user: User)
}

class UserRepository(private val dao: UserDao) {
suspend fun insertUser(user: User) = withContext(Dispatchers.IO) {
dao.insert(user)
}
}

fun main() = runBlocking {
val repository = UserRepository(/* DAO instance */)
launch { repository.insertUser(User(1, "John")) }
}

14.29 并发 API 调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import kotlinx.coroutines.*

suspend fun fetchData1(): String = withContext(Dispatchers.IO) {
delay(1000)
"Data 1"
}

suspend fun fetchData2(): String = withContext(Dispatchers.IO) {
delay(1500)
"Data 2"
}

fun main() = runBlocking {
val deferred1 = async { fetchData1() }
val deferred2 = async { fetchData2() }
val results = awaitAll(deferred1, deferred2)
println("Results: $results")
}

14.30 超时处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import kotlinx.coroutines.*

suspend fun longRunningTask(): String = withContext(Dispatchers.IO) {
delay(3000)
"Done"
}

fun main() = runBlocking {
try {
withTimeout(2000L) {
val result = longRunningTask()
println(result)
}
} catch (e: TimeoutCancellationException) {
println("Task timed out")
}
}

参考资料

15. 对象声明

使用 object 创建单例

1
2
3
4
5
6
7
object Singleton {
fun hello() = println("Hello")
}

fun main() {
Singleton.hello() // Hello
}

16. 伴生对象

在类中使用 companion object 定义静态成员

1
2
3
4
5
6
7
8
9
class MyClass {
companion object { // 相当于静态方法/字段,提供类级别的静态成员支持
fun create() = MyClass() // 伴生对象中的工厂函数
}
}

fun main() {
val instance = MyClass.create()
}

等价于

1
2
3
4
5
public class MyClass {
public static MyClass create() {
return new MyClass();
}
}

17. 导入

1
2
3
4
import kotlin.math.PI as MathPI
fun main() {
println(MathPI) // 3.141592653589793
}

18. 异常处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
fun validate(x: Int) {
if (x < 0) throw IllegalArgumentException("Negative not allowed")
}

fun main() {
val result = try {
validate(-1)
"Success"
} catch (e: IllegalArgumentException) {
println("Error: ${e.message}")
"Failed"
} finally {
println("Cleanup")
}
println("Result: $result") // Failed
}

19. 泛型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class Box<T>(val value: T) // 泛型类

fun <T> printItem(item: T) = println(item) // 泛型函数

interface Producer<out T> { // 使用协变 out 限制类型只能作为返回值
fun produce(): T
}
class StringProducer : Producer<String> {
override fun produce() = "Hello"
}

interface Consumer<in T> { // 使用逆变 in 限制类型只能作为参数
fun consume(item: T)
}
class AnyConsumer : Consumer<Any> {
override fun consume(item: Any) = println(item)
}

fun printList(list: List<*>) = println(list) // 通配符 *,类型为 Any?

fun main() {
val intBox = Box(42)
val strBox = Box("Kotlin")
println("${intBox.value}, ${strBox.value}")

printItem(42) // 42
printItem("Kotlin") // Kotlin

val producer: Producer<String> = StringProducer()
println(producer.produce())

val consumer: Consumer<Any> = AnyConsumer()
consumer.consume("Hello")

printList(listOf(1, "A")) // [1, A]
}

20. 自定义注解

1
2
3
4
5
6
7
8
annotation class MyAnnotation(val priority: Int)

@MyAnnotation(1)
fun annotated() = println("Annotated")

fun main() {
annotated()
}

21. 中缀函数

1
2
3
4
5
infix fun Int.plus(x: Int) = this + x // 表达式函数体 = 允许类型推断,代码块函数体 {} 必须显式写出返回类型

fun main() {
println(5 plus 3) // 8
}

22. 运算符重载

1
2
3
4
5
6
7
8
9
data class Point(val x: Int, val y: Int) {
operator fun plus(other: Point) = Point(x + other.x, y + other.y)
}

fun main() {
val p1 = Point(1, 2)
val p2 = Point(3, 4)
println(p1 + p2) // Point(x=4, y=6)
}

23. 内联类(已废弃)

  • 使用 inline class 定义单值包装类,编译时展开为原始类型,避免对象分配。
  • 不支持接口实现。
  • 使用 @JvmInline value class 替代 inline class
  • 不可扩展,不可被集成。
1
2
3
4
5
6
inline class Name(val value: String)

fun main() {
val name = Name("Kotlin")
println(name.value) // Kotlin
}

内联类和内联值类特性:

能做吗 描述
❌ 继承类 不行,value class 不能继承任何类(除了 Any
❌ 被继承 不行,value class 自身也不能被继承
✅ 实现接口 可以实现接口
✅ 内联优化 可以提升性能,避免创建对象

24. 内联值类

  • 场景:当需要包装单一值并保持性能(如 ID、计数、单位类型),使用内联值类;复杂对象仍使用普通 data class
  • 为什么不直接使用原始类型?
    • 内联值类为原始类型添加语义,防止误用。
    • 代码可读性增加。
    • 内联值类允许为原始类型添加方法或实现接口,封装特定逻辑,而不增加运行时开销。
    • 领域驱动设计(DDD)。在复杂系统中,内联值类支持领域建模,用类型区分不同概念(如 OrderId vs ProductId),提高代码一致性。
    • 内联值类可以在构造时验证值,防止非法状态,而原始类型无法限制。
    • 内联值类通过 @JvmInline 在编译时替换为底层原始类型(如 Int),几乎无额外内存或性能开销,接近直接使用原始类型的效率。
1
2
3
4
5
6
7
8
9
10
11
@JvmInline
value class UserId(val id: Int) : Comparable<UserId> {
override fun compareTo(other: UserId): Int = id.compareTo(other.id)
}

fun main() {
val userId = UserId(42)
println(userId.id) // 输出 42
println(userId > UserId(40)) // 输出 true
// 编译后,userId 被替换为 Int,支持接口方法
}

25. 无符号整数

  • UInt:32 位无符号整数,ULong:64 位,加 uU 后缀。
  • 编译为有符号整数,运行时模拟无符号行为。
1
2
3
4
5
fun main() {
val uint: UInt = 42u
val ulong: ULong = 123UL
println("$uint, $ulong")
}

26. SAM 转换改进

单方法接口支持 Lambda 转换

1
2
3
4
5
6
7
8
fun interface Action {
fun run()
}

fun main() {
val action = Action { println("Run") }
action.run()
}

27. 密封接口和密封类

  • sealed 修饰符表示 Expr接口(或类)只能在同一模块(通常是同一文件或项目)内被实现。
  • 外部代码无法创建新的Expr子类,确保Expr的所有可能实现(如Num)是已知的。
  • 对比普通接口,sealed 减少了运行时类型转换(如 as Num)的需要。
  • 意义:保证类型系统的封闭性,防止意外扩展,适合建模有限的类型集合(如表达式树)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
sealed interface Expr

data class Num(val value: Int) : Expr {
operator fun plus(other: Num) = Num(value + other.value)
}

data class Add(val left: Num, val right: Num) : Expr

fun main() {
val expr1: Expr = Num(42)
println((expr1 as Num).value) // 不够优雅
val expr2: Expr = Add(Num(2), Num(3))
println(
when (expr2) {
is Add -> (expr2.left + expr2.right)
is Num -> expr2.value
}
)
}

Kotlin 的 密封类(sealed class) 是一种用于表示受限继承结构的类,适合用来表达有限状态、事件、指令等类型的场景。sealed class 表示一个封闭的类层次结构,所有子类必须定义在同一个文件中。它是 抽象类 的一种变体,用于替代 enum 或 if/else 的分支判断,且能结合 when 表达式使用,非常强大。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
sealed class Result<out T> {
data class Success<out T>(val data: T) : Result<T>()
data class Error(val exception: Throwable) : Result<Nothing>()
object Loading : Result<Nothing>()
}

fun fetchData(): Result<String> {
return try {
val result = "Hello"
Result.Success(result)
} catch (e: Exception) {
Result.Error(e)
}
}

fun handle(result: Result<String>) {
when (result) {
is Result.Success -> println("Got data: ${result.data}")
is Result.Error -> println("Error: ${result.exception.message}")
Result.Loading -> println("Loading...")
}
}

inline fun <T> Result<T>.onSuccess(action: (T) -> Unit): Result<T> {
if (this is Result.Success) action(data)
return this
}

inline fun <T> Result<T>.onError(action: (Throwable) -> Unit): Result<T> {
if (this is Result.Error) action(exception)
return this
}

fetchData()
.onSuccess { println("Success: $it") }
.onError { println("Error: ${it.message}") }

👉 由于 Result 是密封类,when 表达式必须覆盖所有子类,否则编译报错(如果没有 else 分支)。

28. IO

1
2
3
4
5
import java.io.File
fun main() {
File("test.txt").writeText("Hello")
println(File("test.txt").readText()) // Hello
}

29. 反射和运行时

需要在build.gradle.kts文件中添加:

1
2
3
dependencies {
implementation(kotlin("reflect"))
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
fun hello() = println("Hello")

data class Person(val name: String)

fun main() {
val ref1 = String::class // 类引用
println(ref1.simpleName) // String

val ref2 = ::hello // 函数引用,仅限顶层或成员函数
ref2() // Hello

val props = Person::class.members
println(props.map { it.name }) // [name]
}

30. 属性委托

  • 使用by将属性委托给代理对象
  • lazy首次访问时初始化,不可重新赋值。默认同步,需明确模式(如 LazyThreadSafetyMode.NONE)。
  • Delegates.observable:属性变化监听。
  • lazyobservableKotlin 提供的内置委托。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import kotlin.properties.Delegates
fun main() {
// lazy
val lazyVal: String by lazy {
println("Computed")
"Lazy"
}
println(lazyVal) // Computed, Lazy
println(lazyVal) // Lazy(不再计算)

// observable
var obsVal: String by Delegates.observable("Init") {
property, old, new -> println("${property.name}: $old -> $new")
}
obsVal = "New" // obsVal: Init -> New
obsVal = "Final" // obsVal: New -> Final
}

31. 类委托

  • 使用by将接口实现委托给对象
  • 组合优于继承,使用委托组合多个对象的行为
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
interface Printer {
fun printMessage(message: String)
}

class ConsolePrinter : Printer {
override fun printMessage(message: String) {
println("Console: $message")
}
}

class DelegatingPrinter(private val printer: Printer) : Printer by printer {
// 可选择重写部分方法
override fun printMessage(message: String) {
println("Delegating: $message") // 这里是装饰器模式,包装现有实现,添加额外功能(如日志、验证)
printer.printMessage(message) // 调用委托对象
}
}

fun main() {
val consolePrinter = ConsolePrinter()
// 这里可以通过更换委托对象,动态改变行为。例如:切换 Printer 实现为文件打印或网络打印
val delegatingPrinter = DelegatingPrinter(consolePrinter)
delegatingPrinter.printMessage("Hello, Kotlin!") // 输出:
// Delegating: Hello, Kotlin!
// Console: Hello, Kotlin!
}

32. 作用域函数

Kotlin 的作用域函数(Scope Functions)是让你能更优雅地处理对象初始化、配置、临时作用域和链式调用的语法工具。常用的有以下 5 个:

函数 用途简记 返回值 引用名
let null安全、链式处理 Lambda结果 it
run 初始化 + 返回值 Lambda结果 this
with 多操作 + 返回值 Lambda结果 this
apply 初始化 + 返回对象 原对象 this
also 调试副作用 + 返回对象 原对象 it

🔹 1. let:用 it 作为对象引用

适合做null 检查和链式操作。

1
2
3
4
val name: String? = "Kotlin"
name?.let {
println("名字是 $it") // it 指向 name
}

🔹 2. run:用 this 引用对象,返回表达式结果

适合对象初始化 + 返回值计算

1
2
3
4
5
val length = "Kotlin".run {
println("字符串是 $this")
length // 返回最后一行,即 length 的值
}
println(length) // 6

🔹 3. with:不是扩展函数,作用于已有对象

适合对对象做多个操作但不返回原对象,而是返回表达式值。

1
2
3
4
5
6
7
val sb = StringBuilder()
val result = with(sb) {
append("Hello, ")
append("World!")
toString()
}
println(result) // Hello, World!

🔹 4. apply:用 this,返回对象自身

适合构造对象并链式设置属性

1
2
3
4
5
6
7
8
data class User(var name: String = "", var age: Int = 0)

fun main() {
val user = User().apply {
name = "124"
age = 25
}
}

🔹 5. also:用 it,返回对象自身

适合用于链式调用中插入副作用逻辑(如日志、调试)

1
2
3
4
val list = mutableListOf(1, 2, 3)
.also { println("原始列表: $it") }
.apply { add(4) }
.also { println("添加元素后: $it") }

33. 内联函数

关键字 意义
inline 函数和 lambda 代码都在编译期被“展开复制”到调用处,提高性能
noinline 在 inline 函数中,禁止某个 lambda 被内联
crossinline 在 inline 函数中,禁止 lambda 使用 return 非局部返回

inline

✅ 1. inline:让函数和 lambda “展开” 到调用处,提高性能

1
2
3
4
5
6
7
8
9
10
11
inline fun doSomething(block: () -> Unit) {
println("Before block")
block() // 会被“复制粘贴”到调用处
println("After block")
}

fun main() {
doSomething {
println("Doing work")
}
}

编译后近似于 👇:

1
2
3
4
5
fun main() {
println("Before block")
println("Doing work")
println("After block")
}

✅ 优点:消除函数调用开销、避免创建 Function 对象(尤其在频繁调用的 lambda 中)


noinline

⚠️ 2. noinline:阻止某个 lambda 被内联(因为你可能要传递它)

1
2
3
4
5
6
7
8
inline fun doOps(
inlineBlock: () -> Unit,
noinline logging: () -> Unit // ❗ 禁止内联
) {
inlineBlock() // 内联
val func = logging // ❗ 如果不加 noinline 会编译错误,因为不能传递被内联的 lambda
func()
}

你必须加 noinline,否则无法将 lambda 存成变量或传给其他函数。


crossinline

🚫 3. crossinline:禁止 lambda 用 return 做“非局部返回”

🔸 默认情况下,内联 lambda 可以直接 return,但有风险。

1
2
3
4
5
6
7
8
9
10
11
inline fun higherOrder(block: () -> Unit) {
println("Before")
block()
println("After") // ⚠️ 如果 block 里直接 return,这行永远不会执行
}

fun test() {
higherOrder {
return // 🚫 这是“非局部返回”:会从 test() 函数直接返回
}
}

要禁止这种“跳出上层函数”的行为,加 crossinline

1
2
3
4
5
6
7
inline fun higherOrder(crossinline block: () -> Unit) {
println("Before")
val r = Runnable {
block() // ✅ 现在 block() 里面不能写 return 了
}
r.run()
}

✅ 总结对照表

关键字 用途说明
inline 将函数和 lambda 在调用处展开,提升性能、支持非局部 return
noinline 禁止某个 lambda 被内联(可传递为变量)
crossinline 禁止 lambda 使用非局部 return(可用在回调、线程等)

📌 什么时候用它们?

场景 关键字
高频调用、性能敏感的高阶函数 inline
lambda 需要传递或存为变量 noinline
lambda 不能用 return(如线程、回调) crossinline