Kotlin 集合操作:map、filter、forEach
- 打开 任意支持 Kotlin 的代码编辑器(如 IntelliJ IDEA 或 VS Code),新建 标准 Kotlin 项目或单文件脚本。
- 定位 至主程序入口,通常命名为
Main.kt,清理 模板代码,仅保留fun main() {}结构。 - 声明 基础数据集合,定义 包含混合业务数据的整数列表。在函数体内输入以下初始化代码:
val numbers = listOf(10, 25, 8, 42, 33) println("原始数据: $numbers") ``` 4. **运行** 当前文件,**核对** 控制台输出是否为 `[10, 25, 8, 42, 33]`。此列表将作为后续所有转换与过滤操作的基准源,其类型为只读集合(即初始化后无法增删元素,保障数据安全)。 --- 5. **理解** `map` 的核心作用:对集合中的每一个元素执行相同计算,并按原顺序收集结果生成全新列表。可将其视为“批量加工厂”,进去多少个零件,出来多少个成品,仅外观规格改变。 6. **调用** `map` 函数实现数值翻倍。将主逻辑替换为以下代码: ```kotlin val doubled = numbers.map { it * 2 } println("翻倍结果: $doubled") - 解析 代码结构:
map后紧跟花括号{ },内部包裹的逻辑称为 Lambda 表达式(一种无需命名、直接写在调用处的小代码块)。it是 Kotlin 默认参数名,代表当前循环到的单个元素。 - 执行 编译运行,确认 终端输出
[20, 50, 16, 84, 66]。原始numbers列表内容保持不变,证明map属于非破坏性操作,内存中实际存在两份独立数据。 - 切换 数据类型,测试格式转换能力。编写 将数字包装为字符串的代码:
val labeled = numbers.map { num -> "数据项_$num" } println("标签列表: $labeled") - 注意 箭头符号
->的使用场景:当单参数默认名it语义不清晰,或需处理多个参数时,必须手动声明变量名(如num),后接->分隔具体业务逻辑。 - 运行 验证,检查 输出结果为
[数据项_10, 数据项_25, 数据项_8, 数据项_42, 数据项_33],确认类型映射准确无误。
-
理解
filter的核心作用:根据预设条件对集合进行逐元素校验,保留返回true的数据,剔除返回false的数据。最终列表长度动态变化,如同“精准筛网”。 -
应用
filter提取符合区间与奇偶规则的元素。输入 以下筛选逻辑:val valid = numbers.filter { it > 15 && it % 2 != 0 } println("有效数据: $valid") ``` 14. **拆解** 判定条件:`it > 15` 划定下限,`&&`(逻辑与)要求两个条件必须同时满足,`it % 2 != 0`(取模运算)过滤掉所有偶数。仅当整个表达式结果为布尔值 `true` 时,当前元素才会进入结果集。 15. **执行** 代码,**对比** 输出 `[25, 33]`。`10` 和 `8` 因未达阈值被拦截,`42` 因是偶数被拦截,逻辑执行严格符合预期。 16. **测试** 零匹配边界情况。临时修改条件为 `it > 100`,**观察** 终端打印空列表 `[]`。`filter` 内部已做安全处理,不会因无数据而抛出异常或中断程序。 --- 17. **理解** `forEach` 的核心作用:按索引顺序遍历集合,对每个元素执行指定动作。该操作不生成新列表,也不返回有效数据,专用于触发“副作用”(即对外部环境产生影响的操作,如打印日志、写入磁盘、刷新 UI)。 18. **编写** 基础遍历打印逻辑。**替换** 函数体为以下代码: ```kotlin numbers.forEach { value -> println("处理节点: $value") } -
区分 函数特性:此处无需使用
val result =接收返回值,因为forEach的返回类型固定为Unit(代表“无实质结果”,仅表示函数已执行完毕)。 -
运行 脚本,记录 终端逐行输出五条独立日志,验证遍历顺序严格遵循原始列表的声明次序。
-
模拟 真实业务累加场景,引入 外部可变计数器并遍历更新:
var globalTotal = 0 numbers.forEach { globalTotal += it } println("累计总值: $globalTotal") ``` 22. **检查** 控制台输出 `118`,确认 `forEach` 适用于需要修改外部状态、但不关心中间集合形态的任务流。 --- 23. **掌握** 链式调用机制:Kotlin 允许将多个集合操作符通过点号 `.` 串联,前一个函数的返回结果自动作为后一个函数的输入参数,形成单向数据管道。 24. **构建** 完整处理链路:**筛选** 有效数据 -> **转换** 为平方值 -> **打印** 最终清单。**拼接** 代码如下: ```kotlin numbers .filter { it > 10 } .map { it * it } .forEach { println("最终产出: $it") } -
追踪 数据流转:
filter截留[25, 42, 33]传递给下一环;map接收数组计算平方,生成[625, 1764, 1089];forEach接管末尾负责输出。中间无需声明任何过渡变量。 -
运行 整合脚本,核对 终端依次打印三个平方数,证明管道传递零损耗、逻辑顺序完全由代码书写位置决定。
-
识别 常规集合与序列的性能差异:标准
List操作是“急加载”模式,每一步都会立即计算并生成完整的临时列表;当数据量突破万级时,内存分配与 GC 回收(垃圾清理机制)会拖慢响应速度。 -
启用 延迟计算优化:在链式调用首部插入
asSequence(),将急加载模式切换为“懒加载”(即只有走到最终环节才真正执行计算)。修改首行为:numbers.asSequence() .filter { it > 10 } .map { it * it } .forEach { println("最终产出: $it") } -
验证 执行效果,运行逻辑与输出结果完全一致,但底层已消除中间集合的创建开销,内存占用降至最低。日常开发中,处理超过 5000 条记录或涉及复杂多重过滤转换时,必须 优先采用序列写法。
| 操作符名称 | 输入输出关系 | 返回值类型 | 典型业务场景 | 内存与性能特征 |
|---|---|---|---|---|
map |
一对一完整映射 | 全新集合对象 | 字段格式化、单位换算、模型转换 | 立即生成新数组,数据量大时内存开销成倍增加 |
filter |
多对零或一对多 | 全新集合对象 | 状态剔除、权限拦截、无效数据清洗 | 同样返回新数组,连续调用会堆积多个临时对象 |
forEach |
纯消费遍历 | Unit (无返回值) |
埋点上报、文件逐行写入、界面批量刷新 | 位于管道末端,本身不占额外内存,仅触发外部操作 |
- 规避 空指针异常陷阱:当集合元素本身允许为
null(即可空类型Int?)时,直接调用it * 2会导致编译失败。改用 安全调用符?.与 Elvis 运算符?:(若左侧为空则取右侧默认值)进行防御性编程,将转换逻辑改写为map { num -> (num ?: 0) * 2 },确保空值被替换为零参与计算,程序永不崩溃。

暂无评论,快来抢沙发吧!