第 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)
}
初学阶段先掌握 listOf 和 mutableListOf。遇到 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返回满足条件的所有元素,组成一个新 Listit代表当前元素- 原 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 猜数字游戏的基础上,增加以下功能:
- 记录每次猜测的数字,存到
mutableListOf<Int>() - 游戏结束后,用 for 循环打印所有猜测记录
- 统计猜错了几次
- 给出评语:使用 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 后,你应该能做到:
- 能用
listOf和mutableListOf创建列表 - 能说出
listOf和mutableListOf的区别 - 能用
[index]访问列表元素 - 能用
val声明可变 List 并理解其含义 - 能用
for (item in list)遍历列表元素 - 能用
for (i in list.indices)遍历索引 - 能用
withIndex()同时获取索引和元素 - 能用
..、until、downTo、step控制循环范围 - 能使用
filter、map、forEach等集合操作 - 能区分
for、while、do-while的使用场景 - 能说出
break和continue的区别 - 能避免索引越界、遍历时修改集合等常见错误
十、今日总结
Day 5-6 的核心是"用集合存数据,用循环处理数据":
- List 是一组有序数据,不可变用
listOf,可变用mutableListOf - for 循环 是集合处理的主力,配合
indices和withIndex灵活遍历 - filter 和 map 让数据筛选和转换非常简洁
- while 适合不确定循环次数的场景
- 初学阶段优先使用 List,Array 可以暂时放一放
掌握 List 和循环后,下一阶段将进入 函数(function)的学习------你可以把一段代码打包成函数,反复调用而不用复制粘贴。