文章目录

Kotlin 集合操作:map、filter、forEach

发布于 2026-04-06 19:57:51 · 浏览 11 次 · 评论 0 条

Kotlin 集合操作:map、filter、forEach


  1. 打开 任意支持 Kotlin 的代码编辑器(如 IntelliJ IDEA 或 VS Code),新建 标准 Kotlin 项目或单文件脚本。
  2. 定位 至主程序入口,通常命名为 Main.kt清理 模板代码,仅保留 fun main() {} 结构。
  3. 声明 基础数据集合,定义 包含混合业务数据的整数列表。在函数体内输入以下初始化代码:
    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")
  4. 解析 代码结构:map 后紧跟花括号 { },内部包裹的逻辑称为 Lambda 表达式(一种无需命名、直接写在调用处的小代码块)。it 是 Kotlin 默认参数名,代表当前循环到的单个元素。
  5. 执行 编译运行,确认 终端输出 [20, 50, 16, 84, 66]。原始 numbers 列表内容保持不变,证明 map 属于非破坏性操作,内存中实际存在两份独立数据。
  6. 切换 数据类型,测试格式转换能力。编写 将数字包装为字符串的代码:
    val labeled = numbers.map { num -> "数据项_$num" }
       println("标签列表: $labeled")
  7. 注意 箭头符号 -> 的使用场景:当单参数默认名 it 语义不清晰,或需处理多个参数时,必须手动声明变量名(如 num),后接 -> 分隔具体业务逻辑。
  8. 运行 验证,检查 输出结果为 [数据项_10, 数据项_25, 数据项_8, 数据项_42, 数据项_33],确认类型映射准确无误。

  1. 理解 filter 的核心作用:根据预设条件对集合进行逐元素校验,保留返回 true 的数据,剔除返回 false 的数据。最终列表长度动态变化,如同“精准筛网”。

  2. 应用 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")
    }
  3. 区分 函数特性:此处无需使用 val result = 接收返回值,因为 forEach 的返回类型固定为 Unit(代表“无实质结果”,仅表示函数已执行完毕)。

  4. 运行 脚本,记录 终端逐行输出五条独立日志,验证遍历顺序严格遵循原始列表的声明次序。

  5. 模拟 真实业务累加场景,引入 外部可变计数器并遍历更新:

    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") }
  6. 追踪 数据流转:filter 截留 [25, 42, 33] 传递给下一环;map 接收数组计算平方,生成 [625, 1764, 1089]forEach 接管末尾负责输出。中间无需声明任何过渡变量。

  7. 运行 整合脚本,核对 终端依次打印三个平方数,证明管道传递零损耗、逻辑顺序完全由代码书写位置决定。

  8. 识别 常规集合与序列的性能差异:标准 List 操作是“急加载”模式,每一步都会立即计算并生成完整的临时列表;当数据量突破万级时,内存分配与 GC 回收(垃圾清理机制)会拖慢响应速度。

  9. 启用 延迟计算优化:在链式调用首部插入 asSequence(),将急加载模式切换为“懒加载”(即只有走到最终环节才真正执行计算)。修改首行为:

    numbers.asSequence()
        .filter { it > 10 }
        .map { it * it }
        .forEach { println("最终产出: $it") }
  10. 验证 执行效果,运行逻辑与输出结果完全一致,但底层已消除中间集合的创建开销,内存占用降至最低。日常开发中,处理超过 5000 条记录或涉及复杂多重过滤转换时,必须 优先采用序列写法。

操作符名称 输入输出关系 返回值类型 典型业务场景 内存与性能特征
map 一对一完整映射 全新集合对象 字段格式化、单位换算、模型转换 立即生成新数组,数据量大时内存开销成倍增加
filter 多对零或一对多 全新集合对象 状态剔除、权限拦截、无效数据清洗 同样返回新数组,连续调用会堆积多个临时对象
forEach 纯消费遍历 Unit (无返回值) 埋点上报、文件逐行写入、界面批量刷新 位于管道末端,本身不占额外内存,仅触发外部操作
  1. 规避 空指针异常陷阱:当集合元素本身允许为 null(即可空类型 Int?)时,直接调用 it * 2 会导致编译失败。改用 安全调用符 ?. 与 Elvis 运算符 ?:(若左侧为空则取右侧默认值)进行防御性编程,将转换逻辑改写为 map { num -> (num ?: 0) * 2 },确保空值被替换为零参与计算,程序永不崩溃。

评论 (0)

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

扫一扫,手机查看

扫描上方二维码,在手机上查看本文