返回正文
Kotlin 集合与序列
做 Android 开发这么多年,我见过太多人在集合处理上踩坑。明明数据结构很简单,却写得又臭又长,遍历-filter-map 一套下来手机直接卡死。
今天这篇文章,把集合和序列一次性讲透,让你的代码既简洁又高效。
Kotlin 集合体系:先搞清这两个大类
Kotlin 的集合分两大类,这个一定要搞清楚:
不可变集合:只读不写,线程安全
kotlin
// List:有序、可重复
val list = listOf("Android", "Kotlin", "Java")
// Set:无序、不可重复
val set = setOf("A", "B", "A") // 结果:[A, B],自动去重
// Map:键值对
val map = mapOf("name" to "张三", "age" to 25)1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
可变集合:可以增删改
java
// MutableList:可变列表
val mutableList = mutableListOf("Android", "Kotlin")
mutableList.add("Java") // ✅ 可以添加
mutableList[0] = "Flutter" // ✅ 可以修改
// MutableSet 和 MutableMap 同理
val mutableMap = mutableMapOf("name" to "张三")
mutableMap["age"] = 25 // 添加键值对1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
实战建议:优先用不可变集合 listOf,只有需要修改时才用 mutableListOf。这样代码更安全,意图更清晰。
常用集合函数:链式调用才是精髓
Kotlin 给集合加了大量扩展函数,链式调用起来那叫一个爽:
kotlin
val users = listOf(
User("张三", 25, "北京"),
User("李四", 30, "上海"),
User("王五", 25, "北京"),
User("赵六", 28, "深圳")
)
// 过滤 + 转换 + 分组,链式调用
val result = users
.filter { it.age > 25 } // 过滤年龄大于25的
.sortedBy { it.name } // 按名字排序
.groupBy { it.city } // 按城市分组
// 输出:{上海=[李四], 深圳=[赵六]}1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
常用函数速查
| 函数 | 作用 | 示例 |
|---|---|---|
map | 转换每个元素 | list.map { it * 2 } |
filter | 过滤元素 | list.filter { it > 3 } |
flatMap | 先转换再扁平化 | list.flatMap { it.children } |
reduce | 聚合为单个值 | list.reduce { acc, n -> acc + n } |
groupBy | 按条件分组 | list.groupBy { it.category } |
sortedBy | 排序 | list.sortedBy { it.age } |
take | 取前n个 | list.take(5) |
distinct | 去重 | list.distinct() |
Sequence:Iterable 的性能杀手
这是今天的主角,很多人根本不知道 Sequence 的存在,导致代码在大数据量时卡成 PPT。
普通集合的致命问题:中间集合
java
// 你写的代码
(1..1000000)
.filter { it % 2 == 0 } // 第一步:生成50万个元素的集合
.map { it * 2 } // 第二步:再生成50万个元素的集合
.take(10) // 第三步:再生成10个元素的集合
.toList()1
2
3
4
5
6
2
3
4
5
6
问题在哪:每一步都创建新的中间集合,100万数据要遍历3次,内存占用爆炸!
Sequence 的解决方案:惰性执行
kotlin
// 加上 asSequence()
(1..1000000)
.asSequence()
.filter { it % 2 == 0 } // 不执行,只记录
.map { it * 2 } // 不执行,只记录
.take(10) // 不执行,只记录
.toList() // 🔥 这里才开始执行!1
2
3
4
5
6
7
2
3
4
5
6
7
原理:Sequence 是惰性的,中间操作不执行、不创建集合,只有碰到终止操作(如 toList()、forEach())才一次性执行到底。而且是纵向执行——处理完一个元素再去处理下一个,找到10个就立刻停止,不会傻傻遍历全部100万数据。
性能对比实测
kotlin
fun main() {
val count = 1_000_000
// Iterable:耗时 20~60ms
val r1 = (1..count).filter { it % 2 == 0 }.map { it * 2 }.take(10).toList()
// Sequence:耗时 0~1ms
val r2 = (1..count).asSequence().filter { it % 2 == 0 }.map { it * 2 }.take(10).toList()
// 性能差距:几十倍到上百倍!
}1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
什么时候用 Sequence?记住三条规则
- 数据量 > 1000 条 → 用 Sequence
- 链式操作 ≥ 2 步 → 用 Sequence
- 使用 take/limit 只取前几个 → 必须用 Sequence
反过来说:小数据量、单步操作,用普通集合就行,Sequence 有额外的创建开销。
kotlin
// 小数据量:普通集合即可
val smallList = listOf(1, 2, 3, 4, 5)
val result = smallList.filter { it > 2 } // 不用 asSequence()
// 大数据量 + 多步操作:必须用 Sequence
val bigList = dao.getAllUsers() // 假设有10万条
val result = bigList
.asSequence()
.filter { it.isActive }
.map { it.name }
.take(10)
.toList()1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
Pair 和 Triple:临时返回多个值
有时候函数需要返回两个或三个值,以前得新建一个类,现在直接用内置的:
kotlin
// Pair:两个值
fun getUserInfo(): Pair<String, Int> {
return Pair("张三", 25)
}
// 解构获取
val (name, age) = getUserInfo()
// 更简洁的写法
fun getUser() = "李四" to 30
// Triple:三个值
data class Result(val success: Boolean, val data: String?, val error: String?)1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
实战场景:网络请求结果解析
java
sealed class ApiResult<out T> {
data class Success<T>(val data: T) : ApiResult<T>()
data class Error(val message: String) : ApiResult<Nothing>()
object Loading : ApiResult<Nothing>()
}1
2
3
4
5
2
3
4
5
集合性能避坑指南
坑1:循环中创建集合
java
// ❌ 错误:每次循环都创建新集合
for (item in list) {
val filtered = list.filter { it.id == item.id }
}
// ✅ 正确:先转成 Map,O(1) 查找
val map = list.associateBy { it.id }
for (item in list) {
val filtered = map[item.id]
}1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
坑2:频繁判断元素是否存在
kotlin
// ❌ 错误:O(n) 查找,数据量大时很慢
if (list.contains(item)) { ... }
// ✅ 正确:Set 的 contains 是 O(1)
val set = list.toSet()
if (set.contains(item)) { ... }1
2
3
4
5
6
2
3
4
5
6
坑3:预分配容量
kotlin
// ❌ 错误:默认容量10,添加1000个元素会扩容多次
val list = mutableListOf<String>()
// ✅ 正确:预分配容量
val list = ArrayList<String>(1000)1
2
3
4
5
2
3
4
5
Android 开发实战场景
场景1:Room 数据库查询结果处理
kotlin
@Query("SELECT * FROM users")
suspend fun getAllUsers(): List<User>
// ViewModel 中处理
viewModelScope.launch {
val users = userDao.getAllUsers()
.asSequence()
.filter { !it.isDeleted }
.sortedByDescending { it.lastLoginTime }
.take(20)
.toList()
_users.value = users
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
场景2:多层嵌套列表扁平化
kotlin
val categories = listOf(
Category("科技", listOf("AI", "5G", "芯片")),
Category("娱乐", listOf("电影", "音乐", "游戏"))
)
// 用 flatMap 获取所有标签
val allTags = categories.flatMap { it.tags }
// 结果:[AI, 5G, 芯片, 电影, 音乐, 游戏]1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
场景3:数据分组展示
kotlin
val newsList = newsDao.getAllNews()
// 按类型分组
val groupedNews = newsList.groupBy { it.category }
// 遍历输出
groupedNews.forEach { (category, news) ->
println("$category: ${news.size} 条")
}1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
V 0.13.13 |
基于 MIT Licensed版权所有 © 2009- 2026 CMONO.NET
本站访客数
--次 本站总访问量
--人次 