搞懂 Kotlin 的 List、Set、Map、HashMap、LinkedHashMap,以及 asSequence() 的底层原理与实战场景。

一、集合家族总览

在 Kotlin 中,集合是最常用的数据结构之一,主要分为三类:

类型 用途 是否有序 是否允许重复 常见实现
List 有序队列 ArrayList, MutableList
Set 去重集合 ⚠️(看实现) HashSet, LinkedHashSet
Map 键值对映射表 ⚠️(看实现) key❌ value✅ HashMap, LinkedHashMap

可变 vs 只读

  • List, Set, Map只读视图(不能增删改)

  • MutableList, MutableSet, MutableMap可变集合

二、各集合的核心特征

1. List / MutableList

👉 有序可重复,像"排队单子"。

Kotlin 复制代码
val nums = mutableListOf(1, 1, 2)
nums.add(3)
nums.remove(1)         // 删除第一个 1
nums.removeAll { it == 1 } // 删除所有 1
println(nums)          // [2, 3]

常用实现:

  • ArrayList() → 最常见

  • CopyOnWriteArrayList() → 多线程读多写少

2. Set / MutableSet

👉 自动去重。无论你加几次同样元素,只留一份。

Kotlin 复制代码
val set = mutableSetOf(1, 1, 2)
println(set) // [1, 2]

常见实现:

  • HashSet → 无序,高效

  • LinkedHashSet → 按插入顺序保存

  • TreeSet → 自动排序(需要可比较类型)

3. Map / MutableMap

👉 键值对结构(key → value),key 唯一,后写会覆盖前写。

Kotlin 复制代码
val map = mutableMapOf<Int, String>()
map[1] = "A"
map[1] = "B" // 覆盖
println(map) // {1=B}

常见实现:

  • HashMap:高效、无序

  • LinkedHashMap:保序

  • ConcurrentHashMap:多线程安全

三、关键集合实现对比表

类型 是否有序 是否去重 是否可变 说明
listOf() 只读列表
mutableListOf() 可增删改
setOf() ⚠️ 只读去重集合
mutableSetOf() ⚠️ 可增删改的去重集合
mapOf() ⚠️ ✅(key) 只读映射表
mutableMapOf() ⚠️ ✅(key) 可增删改映射表
HashMap ✅(key) 无序高效
LinkedHashMap ✅(key) 有序可改

四、实战:事件队列模型(真实场景)

场景:机器人上报"事件",同一设备可能重复上报。

Kotlin 复制代码
data class DeviceRoute(
    val targetId: String,
    val command: String
)

// 允许重复、保序
private val targetIdList = mutableListOf<DeviceRoute>()

fun addEvent(id: String, cmd: String) {
    targetIdList.add(DeviceRoute(id, cmd))
}

/** 按 command 获取全部 id(允许重复) */
fun getTargetIds(command: String): List<String> {
    return targetIdList.asSequence() // ← 关键点在这里
        .filter { it.command == command }
        .map { it.targetId }
        .toList()
}

/** 删除一个事件(只删第一个匹配项) */
fun removeOne(id: String, cmd: String): Boolean {
    return targetIdList.remove(DeviceRoute(id, cmd))
}

/** 删除所有匹配事件 */
fun removeAll(id: String, cmd: String): Boolean {
    return targetIdList.removeAll { it.targetId == id && it.command == cmd }
}

👉 用 List 因为要保留所有事件(包括重复),

👉 Set 会去重,不适合事件流;

👉 Map key 唯一,也会覆盖旧数据。

五、重点:asSequence() 到底干嘛?

很多人一开始看到这句:

Kotlin 复制代码
targetIdList.asSequence()
    .filter { it.command == command }
    .map { it.targetId }
    .toList()

会疑惑:"asSequence() 有啥用?"

✅ 1. 定义

asSequence() 会把集合转为一个 惰性(lazy)序列

它不会立刻执行 filter/map,而是等到"终止操作"再逐个计算。

✅ 2. 原理对比

不用 asSequence:
Kotlin 复制代码
val result = list
    .filter { it > 10 } // 生成一个新 List
    .map { it * 2 }     // 再生成一个新 List
    .toList()           // 最后又生成一个 List

会构建多个中间集合,占内存、效率低。

用 asSequence:
Kotlin 复制代码
val result = list.asSequence()
    .filter { it > 10 } // 惰性:不马上创建集合
    .map { it * 2 }     // 按需逐个处理
    .toList()           // 到这里才一次性收集结果

只遍历一次列表,更高效,尤其对大数据集合。

✅ 3. 终止操作(trigger 执行)

只有当调用以下之一时才真正执行:

  • 收集:toList(), toSet(), toCollection(...)

  • 查找:first(), firstOrNull(), any(), count()

  • 遍历:forEach, onEach { }.toList()

例如:

Kotlin 复制代码
val res = list.asSequence()
    .filter { it > 10 }
    .map { it * 2 }
    .forEach { println(it) } // 到这里才真正遍历

✅ 4. 优点

优点 说明
🚀 惰性执行 不创建中间集合,效率更高
🧠 可读性强 链式写法直观
💾 节省内存 对大数据集合友好
🔄 保留顺序 不会乱序执行
✅ 与集合方法兼容 可随时 .asSequence() / .toList() 切换

✅ 5. 注意事项

  • Sequence 不是并行流(不像 Java Stream);

  • 如果数据量小,普通集合操作和 Sequence 性能几乎一样;

  • 大量链式计算时 Sequence 更合适。

六、不同结构的典型使用建议

场景 推荐结构 说明
有序、可重复的事件 MutableList 保留所有事件
唯一元素集合 MutableSet / LinkedHashSet 去重场景
键值查表 HashMap / LinkedHashMap 查找快
数据多、要链式过滤 asSequence() 避免中间集合
多线程访问 CopyOnWriteArrayList / ConcurrentHashMap 安全

七、结语:如何选择集合?

你的需求 推荐
要顺序 + 重复 MutableList
要顺序 + 不重复 LinkedHashSet
不关心顺序 + 不重复 HashSet
要查表(key→value) HashMap / LinkedHashMap
想延迟计算、优化性能 .asSequence()

✅ "List 保序可重复,Set 去重,Map 查表,Sequence 优化链路。"

🎯 最后一句话总结

List 是队列,Set 是名单,Map 是字典,asSequence() 是让它们"边走边算"的聪明处理器。

相关推荐
CoderYanger1 天前
动态规划算法-简单多状态dp问题:15.买卖股票的最佳时机含冷冻期
开发语言·算法·leetcode·动态规划·1024程序员节
CoderYanger1 天前
递归、搜索与回溯-FloodFill:33.太平洋大西洋水流问题
java·算法·leetcode·1024程序员节
CoderYanger1 天前
动态规划算法-斐波那契数列模型:2.三步问题
开发语言·算法·leetcode·面试·职场和发展·动态规划·1024程序员节
CoderYanger1 天前
动态规划算法-简单多状态dp问题:16.买卖股票的最佳时机含手续费
开发语言·算法·leetcode·动态规划·1024程序员节
Haha_bj2 天前
七、Kotlin——扩展(Extensions)
android·kotlin
RestCloud2 天前
神州通用数据库的 ETL 集成方案:兼容性与性能实战
数据库·数据仓库·etl·数据处理·数据集成·数据传输·神州通用
urkay-2 天前
Android getDrawingCache 过时废弃
android·java·开发语言·kotlin·iphone·androidx
CoderYanger2 天前
C.滑动窗口-求子数组个数-越短越合法——3258. 统计满足 K 约束的子字符串数量 I
java·开发语言·算法·leetcode·1024程序员节
CoderYanger2 天前
动态规划算法-路径问题:9.最小路径和
开发语言·算法·leetcode·动态规划·1024程序员节
CoderYanger2 天前
动态规划算法-路径问题:7.礼物的最大价值
开发语言·算法·leetcode·动态规划·1024程序员节