Kotlin List / Array 与 for 循环

第 1 周 Day 5-6:Kotlin List / Array 与 for 循环

学习主题:List(列表)、Array(数组)、for 循环、while 循环、集合遍历与常用操作

建议时长:2 天(每天约 1-1.5 小时)

学习目标:能使用 List / Array 存储批量数据,用 for / while 遍历集合,掌握集合常用操作

一、适合读者与学习目标

本文适合正在学习 Kotlin 的零基础或初学者。

如果你已经会用 Kotlin 声明变量、写 if / when 判断,但不知道如何存储一组数据(例如学生列表、购物清单),或者不清楚 for 循环怎么写,可以通过本文掌握 Kotlin 集合和循环的基础写法。

阅读前只需要:

  • 了解 Kotlin 变量声明(val / var)
  • 了解基本数据类型(Int、String、Boolean)
  • 了解 if / when 条件判断

二、为什么学这个

程序中最常见的操作之一就是"处理一批数据"。Android 开发中几乎每个页面都会用到列表:

  • 聊天记录列表
  • 商品展示列表
  • 联系人列表
  • 设置选项列表

如果不会 List 和循环,你会写出这样的代码:

kotlin 复制代码
println(student1)
println(student2)
println(student3)
// ... 100 个学生要写 100 行

学会 List 和 for 循环后,只需要:

kotlin 复制代码
for (student in students) {
    println(student)
}

循环让你用 3 行代码处理 100 条、1000 条甚至更多的数据。

三、Day 1:List 基础与 for 循环

1. 什么是 List

List(列表)是一组有序的数据集合,可以保存多个相同或不同类型的元素。

生活中的例子:

  • 购物清单:["牛奶", "面包", "鸡蛋"]
  • 成绩单:[85, 92, 78, 90]
  • 待办事项:["起床", "学习 Kotlin", "跑步"]

Kotlin 提供两种 List:

类型 创建方法 能否增删元素
不可变 List listOf(...) ❌ 不能修改
可变 List mutableListOf(...) ✅ 可以增删改

2. 不可变 List:listOf()

一旦创建,不能添加、删除或修改元素。

kotlin 复制代码
fun main() {
    val fruits = listOf("苹果", "香蕉", "橘子", "葡萄")
    println(fruits)
}

输出结果:

text 复制代码
[苹果, 香蕉, 橘子, 葡萄]

获取 List 中的某个元素:

kotlin 复制代码
fun main() {
    val fruits = listOf("苹果", "香蕉", "橘子", "葡萄")

    println(fruits[0])  // 第 1 个元素:苹果
    println(fruits[1])  // 第 2 个元素:香蕉
    println(fruits[2])  // 第 3 个元素:橘子
    println(fruits[3])  // 第 4 个元素:葡萄
}

说明:

  • 索引用 [index] 获取,索引从 0 开始
  • 第 1 个元素的索引是 0,第 2 个是 1,以此类推
  • listOf 创建的 List 不可修改,尝试添加或删除元素会编译报错

获取 List 的大小:

kotlin 复制代码
fun main() {
    val fruits = listOf("苹果", "香蕉", "橘子")
    println("List 中有 ${fruits.size} 个元素")  // 输出:List 中有 3 个元素
}

3. 可变 List:mutableListOf()

可以在创建后添加、删除或修改元素。

kotlin 复制代码
fun main() {
    val shoppingList = mutableListOf("牛奶", "面包")
    println("初始:$shoppingList")

    // 添加元素
    shoppingList.add("鸡蛋")
    println("添加后:$shoppingList")

    // 在指定位置插入
    shoppingList.add(0, "苹果")  // 在索引 0 处插入
    println("插入后:$shoppingList")

    // 删除元素
    shoppingList.remove("面包")
    println("删除后:$shoppingList")

    // 按索引删除
    shoppingList.removeAt(1)
    println("按索引删除后:$shoppingList")

    // 修改元素
    shoppingList[0] = "西瓜"
    println("修改后:$shoppingList")
}

输出结果:

text 复制代码
初始:[牛奶, 面包]
添加后:[牛奶, 面包, 鸡蛋]
插入后:[苹果, 牛奶, 面包, 鸡蛋]
删除后:[苹果, 牛奶, 鸡蛋]
按索引删除后:[苹果, 鸡蛋]
修改后:[西瓜, 鸡蛋]

常用操作速查:

操作 方法 示例
添加到末尾 add(元素) list.add("香蕉")
插入到指定位置 add(索引, 元素) list.add(0, "苹果")
删除指定元素 remove(元素) list.remove("苹果")
删除指定索引 removeAt(索引) list.removeAt(1)
修改元素 list[索引] = 新值 list[0] = "西瓜"
获取元素个数 list.size list.size
判断是否为空 list.isEmpty() list.isEmpty()
清空列表 list.clear() list.clear()
判断是否包含 list.contains(元素) list.contains("苹果")

4. val 声明的可变 List 可以修改内容

一个容易混淆的点:用 val 声明的 mutableListOf,不能重新赋值,但可以修改里面的元素。

kotlin 复制代码
fun main() {
    val list = mutableListOf("A", "B", "C")

    list.add("D")       // ✅ 可以修改 List 内部内容
    list[0] = "Hello"   // ✅ 可以修改 List 内部内容

    // list = mutableListOf("X", "Y")  // ❌ 错误:val 不能重新赋值

    println(list)  // [Hello, B, C, D]
}

可以把 val list 理解为:遥控器不能换,但电视节目可以换。

5. for 循环遍历 List

for 循环是处理列表最常用的工具。

遍历元素:

kotlin 复制代码
fun main() {
    val fruits = listOf("苹果", "香蕉", "橘子", "葡萄")

    for (fruit in fruits) {
        println("我喜欢吃$fruit")
    }
}

输出结果:

text 复制代码
我喜欢吃苹果
我喜欢吃香蕉
我喜欢吃橘子
我喜欢吃葡萄

遍历索引:

kotlin 复制代码
fun main() {
    val scores = listOf(85, 92, 78, 90)

    for (i in scores.indices) {
        println("第${i + 1}个学生的成绩:${scores[i]}")
    }
}

输出结果:

text 复制代码
第1个学生的成绩:85
第2个学生的成绩:92
第3个学生的成绩:78
第4个学生的成绩:90

说明:

  • indices 返回索引范围(0 到 size-1)
  • i 是当前索引,从 0 开始

同时获取索引和元素:

kotlin 复制代码
fun main() {
    val names = listOf("张三", "李四", "王五")

    for ((index, name) in names.withIndex()) {
        println("${index + 1}号:$name")
    }
}

输出结果:

text 复制代码
1号:张三
2号:李四
3号:王五

withIndex() 返回一个包含索引和元素的对象,用 (index, name) 解构出来使用。

6. for 循环遍历范围

除了遍历 List,for 循环也可以直接遍历数字范围。

kotlin 复制代码
fun main() {
    // 从 1 到 5(包含 5)
    for (i in 1..5) {
        println(i)
    }
    println("---")

    // 从 1 到 4(不包含 5)
    for (i in 1 until 5) {
        println(i)
    }
    println("---")

    // 从 5 到 1(反向)
    for (i in 5 downTo 1) {
        println(i)
    }
    println("---")

    // 步长为 2
    for (i in 1..10 step 2) {
        println(i)
    }
}

输出结果:

text 复制代码
1
2
3
4
5
---
1
2
3
4
---
5
4
3
2
1
---
1
3
5
7
9

范围写法速查:

写法 含义 示例结果
1..5 1 到 5(含 5) 1, 2, 3, 4, 5
1 until 5 1 到 4(不含 5) 1, 2, 3, 4
5 downTo 1 5 到 1(反向) 5, 4, 3, 2, 1
1..10 step 2 1 到 10,步长 2 1, 3, 5, 7, 9
10 downTo 1 step 3 10 到 1,步长 3 10, 7, 4, 1

7. 循环内的 break 和 continue

kotlin 复制代码
fun main() {
    val scores = listOf(85, 92, 45, 78, 90)

    println("及格成绩(跳过不及格):")
    for (score in scores) {
        if (score < 60) {
            continue  // 跳过当前循环,进入下一次
        }
        println(score)
    }

    println("---")

    println("找到第一个不及格就停止:")
    for (score in scores) {
        if (score < 60) {
            println("第一个不及格:$score")
            break  // 结束整个循环
        }
        println("$score 及格")
    }
}

输出结果:

text 复制代码
及格成绩(跳过不及格):
85
92
78
90
---
找到第一个不及格就停止:
85 及格
92 及格
第一个不及格:45

说明:

  • continue:跳过本次循环的剩余代码,进入下一次循环
  • break:立即退出整个循环

四、Day 2:Array 基础、while 循环与集合操作

1. 什么是 Array

Array(数组)和 List 类似,也是一组有序数据的容器。区别在于:

特性 List Array
创建方式 listOf(...) arrayOf(...)
底层类型 接口,有多种实现 固定大小的连续内存
大小能否变 MutableList 可以 ❌ 固定大小
元素能改 MutableList 可以 ✅ 可以修改元素
何时使用 一般情况优先用 List 需要固定大小或 Java 互操作时

2. 创建和使用 Array

kotlin 复制代码
fun main() {
    // 创建数组
    val numbers = arrayOf(1, 2, 3, 4, 5)
    val names = arrayOf("张三", "李四", "王五")
    val mixed = arrayOf(1, "Hello", true, 3.14)  // 混合类型

    // 访问元素
    println(names[0])  // 张三
    println(names[1])  // 李四

    // 修改元素
    names[0] = "赵六"
    println(names[0])  // 赵六

    // 遍历数组
    for (name in names) {
        println(name)
    }
}

创建基本类型数组(性能更好):

kotlin 复制代码
fun main() {
    val ints = intArrayOf(1, 2, 3, 4, 5)
    val doubles = doubleArrayOf(1.0, 2.5, 3.14)
    val bools = booleanArrayOf(true, false, true)
}

初学阶段先掌握 listOfmutableListOf。遇到 Java 互操作或需要固定大小的场景再使用 Array。

3. while 循环

在 Day 3-4 的猜数字游戏中已经见过 while 了。这里系统介绍一下。

while:先判断,再执行

kotlin 复制代码
fun main() {
    var count = 0

    while (count < 5) {
        println("count = $count")
        count++
    }
}

输出结果:

text 复制代码
count = 0
count = 1
count = 2
count = 3
count = 4

如果条件一开始就不成立,while 内部一次都不会执行。

do-while:先执行,再判断

kotlin 复制代码
fun main() {
    var count = 0

    do {
        println("count = $count")
        count++
    } while (count < 5)
}

输出结果和 while 一样,但 do-while 保证至少执行一次:

kotlin 复制代码
fun main() {
    var count = 10

    while (count < 5) {
        println("while:$count")  // 不会执行
    }

    do {
        println("do-while:$count")  // 会执行一次
    } while (count < 5)
}

输出结果:

text 复制代码
do-while:10

for 和 while 如何选择?

场景 推荐
遍历已知集合或范围 for
不知道循环次数,需要等待条件满足 while
至少执行一次再判断 do-while

4. List 常用函数式操作

Kotlin 为集合提供了很多简洁的操作方法。

filter:筛选

kotlin 复制代码
fun main() {
    val scores = listOf(85, 92, 45, 78, 90, 58, 73)

    val passed = scores.filter { it >= 60 }
    println("及格成绩:$passed")  // [85, 92, 78, 90, 73]

    val failed = scores.filter { it < 60 }
    println("不及格成绩:$failed")  // [45, 58]
}

说明:

  • filter 返回满足条件的所有元素,组成一个新 List
  • it 代表当前元素
  • 原 List 不会改变

map:转换

kotlin 复制代码
fun main() {
    val names = listOf("张三", "李四", "王五")

    val greetings = names.map { "你好,$it" }
    println(greetings)  // [你好,张三, 你好,李四, 你好,王五]
}

forEach:遍历执行操作

kotlin 复制代码
fun main() {
    val fruits = listOf("苹果", "香蕉", "橘子")

    fruits.forEach { fruit ->
        println("今天吃$fruit")
    }
}

输出结果:

text 复制代码
今天吃苹果
今天吃香蕉
今天吃橘子

sorted 和 sortedDescending:排序

kotlin 复制代码
fun main() {
    val scores = listOf(85, 92, 45, 78, 90)
    println("升序:${scores.sorted()}")        // [45, 78, 85, 90, 92]
    println("降序:${scores.sortedDescending()}") // [92, 90, 85, 78, 45]
}

sum、average、max、min:统计

kotlin 复制代码
fun main() {
    val scores = listOf(85, 92, 78, 90)

    println("总和:${scores.sum()}")         // 345
    println("平均值:${scores.average()}")   // 86.25
    println("最大值:${scores.max()}")       // 92
    println("最小值:${scores.min()}")       // 78
    println("个数:${scores.count()}")       // 4
}

组合使用:

kotlin 复制代码
fun main() {
    val scores = listOf(85, 92, 45, 78, 90, 58, 73)

    // 及格成绩的平均分
    val avgPassed = scores.filter { it >= 60 }.average()
    println("及格成绩平均分:$avgPassed")  // 83.6

    // 把及格成绩翻倍
    val doubledPassed = scores.filter { it >= 60 }.map { it * 2 }
    println("及格成绩翻倍:$doubledPassed")
}

说明:

  • 多个操作可以用 . 串联,从左到右执行
  • scores.filter { ... }.average() 先筛选再求平均
  • 这种"链式调用"是 Kotlin 集合操作的一大特色

5. 元素索引、查找与统计

kotlin 复制代码
fun main() {
    val fruits = listOf("苹果", "香蕉", "橘子", "葡萄")

    // 查找元素索引
    println(fruits.indexOf("橘子"))          // 2
    println(fruits.indexOf("西瓜"))          // -1(不存在)

    // 查找最后一个匹配的索引
    val numbers = listOf(1, 2, 3, 2, 1)
    println(numbers.lastIndexOf(2))          // 3

    // 判断是否存在
    println("香蕉" in fruits)               // true
    println("西瓜" in fruits)               // false
    println("西瓜" !in fruits)              // true
}

五、综合示例:成绩管理系统

把两天的知识串起来,写一个控制台成绩管理程序。

kotlin 复制代码
fun main() {
    // 学生名单
    val students = listOf("张三", "李四", "王五", "赵六", "孙七")
    // 对应成绩列表
    val scores = mutableListOf(85, 92, 45, 78, 90)

    println("===== 成绩管理系统 =====")
    println("共有 ${students.size} 名学生\n")

    // 1. 打印所有学生的成绩
    println("--- 全部成绩 ---")
    for ((index, name) in students.withIndex()) {
        val status = if (scores[index] >= 60) "及格" else "不及格"
        println("${index + 1}. $name:${scores[index]} 分($status)")
    }

    // 2. 统计信息
    println("\n--- 统计信息 ---")
    println("平均分:${"%.1f".format(scores.average())}")
    println("最高分:${scores.max()}")
    println("最低分:${scores.min()}")

    // 3. 及格率
    val passCount = scores.count { it >= 60 }
    val passRate = passCount.toDouble() / scores.size * 100
    println("及格率:${"%.1f".format(passRate)}%")

    // 4. 不及格名单
    println("\n--- 不及格名单 ---")
    for ((index, name) in students.withIndex()) {
        if (scores[index] < 60) {
            println("$name:${scores[index]} 分")
        }
    }

    // 5. 排名
    println("\n--- 排名(从高到低) ---")
    // 用 withIndex 获取索引和分数,按分数排序
    val ranked = students.withIndex()
        .sortedByDescending { (index, _) -> scores[index] }
    for ((rank, entry) in ranked.withIndex()) {
        val (index, name) = entry
        println("${rank + 1}. $name:${scores[index]} 分")
    }
}

输出结果:

text 复制代码
===== 成绩管理系统 =====
共有 5 名学生

--- 全部成绩 ---
1. 张三:85 分(及格)
2. 李四:92 分(及格)
3. 王五:45 分(不及格)
4. 赵六:78 分(及格)
5. 孙七:90 分(及格)

--- 统计信息 ---
平均分:78.0
最高分:92
最低分:45
及格率:80.0%

--- 不及格名单 ---
王五:45 分

--- 排名(从高到低) ---
1. 李四:92 分
2. 孙七:90 分
3. 张三:85 分
4. 赵六:78 分
5. 王五:45 分

六、常见错误

错误 1:索引越界

kotlin 复制代码
val fruits = listOf("苹果", "香蕉", "橘子")
println(fruits[3])  // ❌ 运行时错误:IndexOutOfBoundsException
// 只有索引 0、1、2,没有索引 3

解决:访问前先检查索引范围。

kotlin 复制代码
val index = 3
if (index in fruits.indices) {
    println(fruits[index])
} else {
    println("索引 $index 越界")
}

错误 2:混淆 listOf 和 mutableListOf

kotlin 复制代码
val list = listOf(1, 2, 3)
list.add(4)  // ❌ 编译错误:listOf 返回的 List 没有 add 方法

解决:

kotlin 复制代码
val list = mutableListOf(1, 2, 3)
list.add(4)  // ✅

错误 3:for 循环中修改集合

kotlin 复制代码
val list = mutableListOf(1, 2, 3)
for (item in list) {
    list.remove(item)  // ❌ 遍历时修改集合可能抛异常
}

解决:先创建副本再遍历,或使用 removeAll 等方法。

kotlin 复制代码
val list = mutableListOf(1, 2, 3)
val toRemove = list.toList()  // 创建副本
for (item in toRemove) {
    list.remove(item)  // ✅ 在副本上遍历
}

错误 4:... 和 until 混淆

kotlin 复制代码
for (i in 0..list.size) {  // ❌ 多了一个:.. 包含末尾值
    println(list[i])        // size 是 3,但索引最大是 2
}

for (i in 0 until list.size) {  // ✅ until 不包含末尾
    println(list[i])
}

listOf("A", "B", "C").indices 等价于 0 until 3,即索引 0、1、2。

错误 5:while 循环忘记更新条件

kotlin 复制代码
var count = 0
while (count < 5) {
    println(count)
    // count++  // ❌ 忘记递增,死循环!
}

解决:确保循环内部有条件更新的逻辑。

七、练习任务

练习 1:购物清单管理

写一个购物清单管理程序:

kotlin 复制代码
fun main() {
    val cart = mutableListOf<String>()

    // 1. 添加商品
    cart.add("牛奶")
    cart.add("面包")
    cart.add("鸡蛋")

    // 2. 打印清单
    println("--- 购物清单 ---")
    for ((index, item) in cart.withIndex()) {
        println("${index + 1}. $item")
    }

    // 3. 统计
    println("共 ${cart.size} 件商品")

    // 4. 删除已购买的商品
    cart.remove("面包")
    println("购买后面包后:$cart")

    // 5. 检查是否存在
    println("清单中有牛奶吗?${"牛奶" in cart}")
}

分别补全和修改,体会有索引遍历和无索引遍历的区别。

练习 2:数字统计

创建一个包含 10 个随机整数(1 到 100)的 List,完成以下统计:

kotlin 复制代码
import kotlin.random.Random

fun main() {
    val numbers = mutableListOf<Int>()
    for (i in 1..10) {
        numbers.add(Random.nextInt(1, 101))
    }
    println("生成的数字:$numbers")

    // TODO:请补全以下统计
    // 1. 平均值
    // 2. 最大值
    // 3. 最小值
    // 4. 大于 50 的数字个数
    // 5. 偶数个数
}

练习 3:乘法口诀表

用 for 循环打印 9×9 乘法口诀表:

kotlin 复制代码
fun main() {
    for (i in 1..9) {
        for (j in 1..i) {
            print("$j × $i = ${i * j}\t")
        }
        println()
    }
}

输出前 3 行示例:

text 复制代码
1 × 1 = 1
1 × 2 = 2    2 × 2 = 4
1 × 3 = 3    2 × 3 = 6    3 × 3 = 9

请观察双重 for 循环的执行顺序(外层 i,内层 j)。

练习 4:名字筛选

给定一个名字列表,筛选出长度大于等于 3 且包含字母 "a" 的名字。

kotlin 复制代码
fun main() {
    val names = listOf("Tom", "Jack", "Alice", "Bob", "Maria", "Sue", "David")

    // TODO:使用 filter 完成筛选
    val result = names.filter { ??? }
    println(result)  // 期望:[Jack, Maria, David]
}

八、阶段小项目:猜数字游戏增强版

在 Day 3-4 猜数字游戏的基础上,增加以下功能:

  1. 记录每次猜测的数字,存到 mutableListOf<Int>()
  2. 游戏结束后,用 for 循环打印所有猜测记录
  3. 统计猜错了几次
  4. 给出评语:使用 when 根据猜测次数输出
kotlin 复制代码
import kotlin.random.Random

fun main() {
    val target = Random.nextInt(1, 101)
    val guesses = mutableListOf<Int>()
    var guess: Int

    println("猜数字游戏~ 数字范围:1 ~ 100")

    while (true) {
        print("请输入你的猜测:")
        guess = readlnOrNull()?.toIntOrNull() ?: continue
        guesses.add(guess)

        when {
            guess > target -> println("太大了")
            guess < target -> println("太小了")
            else -> {
                println("恭喜!猜对了,数字是 $target")
                break
            }
        }
    }

    // 打印所有猜测记录
    println("\n你的猜测记录:")
    for ((i, g) in guesses.withIndex()) {
        val hint = when {
            g > target -> "偏高"
            g < target -> "偏低"
            else -> "正确"
        }
        println("第 ${i + 1} 次:$g($hint)")
    }

    // 统计
    val wrongCount = guesses.size - 1  // 最后一次是正确答案
    println("共猜测 ${guesses.size} 次,猜错 $wrongCount 次")

    // 评语
    val comment = when (guesses.size) {
        1 -> "一发入魂!"
        in 2..3 -> "运气不错!"
        in 4..6 -> "还行,继续加油"
        in 7..10 -> "下次可以更好"
        else -> "数字这么多可能性,慢慢来~"
    }
    println("评语:$comment")
}

完成标准:

  • 程序可以正常运行
  • 正确使用 List 存储猜测记录
  • 使用 for 循环打印记录
  • 使用 when 输出评语
  • 使用 readlnOrNull() 处理用户输入

九、自测清单

完成 Day 5-6 后,你应该能做到:

  • 能用 listOfmutableListOf 创建列表
  • 能说出 listOfmutableListOf 的区别
  • 能用 [index] 访问列表元素
  • 能用 val 声明可变 List 并理解其含义
  • 能用 for (item in list) 遍历列表元素
  • 能用 for (i in list.indices) 遍历索引
  • 能用 withIndex() 同时获取索引和元素
  • 能用 ..untildownTostep 控制循环范围
  • 能使用 filtermapforEach 等集合操作
  • 能区分 forwhiledo-while 的使用场景
  • 能说出 breakcontinue 的区别
  • 能避免索引越界、遍历时修改集合等常见错误

十、今日总结

Day 5-6 的核心是"用集合存数据,用循环处理数据":

  • List 是一组有序数据,不可变用 listOf,可变用 mutableListOf
  • for 循环 是集合处理的主力,配合 indiceswithIndex 灵活遍历
  • filtermap 让数据筛选和转换非常简洁
  • while 适合不确定循环次数的场景
  • 初学阶段优先使用 List,Array 可以暂时放一放

掌握 List 和循环后,下一阶段将进入 函数(function)的学习------你可以把一段代码打包成函数,反复调用而不用复制粘贴。

十一、参考资料

相关推荐
南滑散修1 小时前
红黑树-非黑即红
java·开发语言
2501_932750262 小时前
Java IO流基础全面详解:字节流、字符流
java·开发语言
冰暮流星2 小时前
javascript之默认事件
开发语言·javascript·ecmascript
fengci.2 小时前
CTF+随机困难题目
android·开发语言·前端·学习·php
l1t2 小时前
DeepSeek总结的Python 3.14.5 发布候选版本
开发语言·python
雪度娃娃2 小时前
设计模式——单例模式
开发语言·c++·设计模式
Cyber4K2 小时前
【Python专项】进阶语法-日志分类与分析(2)
开发语言·前端·python
lbb 小魔仙2 小时前
Python + LangChain 环境搭建完全指南:从零构建本地 RAG 知识库(附 Ollama 本地模型集成)
开发语言·python·langchain
风落无尘2 小时前
Python 包发布全流程:从项目结构到 PyPI 上线,以及我踩过的那些坑
开发语言·python·pip