在日常开发中,我们经常需要处理 "一组数据"------ 比如学生列表、商品信息、用户配置等。Kotlin 的集合框架就是专门用来管理和操作这些 "数据组" 的核心工具,它提供了一套简洁、高效的 API,涵盖了数据的存储、查询、过滤、排序等常见需求。本节课我们将从集合的分类开始,逐步深入讲解 List、Set、Map 三大核心集合,以及能大幅简化代码的 "高阶函数操作"。
一、集合的分类与初始化:先搞懂 "可变" 与 "不可变"
Kotlin 集合框架的核心特点是区分 "不可变集合" 和 "可变集合" ------ 这是为了满足 "数据安全性" 需求(比如避免误修改全局数据)。两者的本质区别是:不可变集合创建后无法修改(不能添加、删除元素),可变集合支持动态修改。
1. 三大集合类型的分类
Kotlin 主要提供三种核心集合类型,每种类型都对应 "不可变" 和 "可变" 两个版本:
集合类型 | 不可变版本(只读) | 可变版本(可读写) | 核心特性 |
---|---|---|---|
列表 | List |
MutableList |
有序、可重复元素 |
集合 | Set |
MutableSet |
无序、不可重复元素 |
映射 | Map |
MutableMap |
键值对(key-value)、键唯一 |
2. 集合的创建方式:一行代码搞定
Kotlin 提供了专门的 "工厂函数" 来创建集合,无需手动 new
,语法简洁。
(1)List 的创建
- 不可变 List:用
listOf()
函数,创建后无法修改; - 可变 List:用
mutableListOf()
函数,支持add
/remove
等操作; - 若需指定初始容量(优化性能):用
mutableListOf(capacity)
(比如mutableListOf(10)
表示初始容量为 10)。
示例:
Kotlin
// 1. 不可变 List:元素按插入顺序保存,可重复
val fruitList: List<String> = listOf("苹果", "香蕉", "苹果", "橙子")
// fruitList.add("葡萄") // 报错:不可变集合没有 add 方法
// 2. 可变 List:可动态修改
val mutableFruitList: MutableList<String> = mutableListOf("苹果", "香蕉")
mutableFruitList.add("葡萄") // 添加元素
mutableFruitList.remove("香蕉") // 删除元素
println(mutableFruitList) // 输出:[苹果, 葡萄]
// 3. 创建空 List(不可变空集合用 emptyList(),可变空集合用 mutableListOf())
val emptyImmutableList: List<Int> = emptyList()
val emptyMutableList: MutableList<Int> = mutableListOf()
(2)Set 的创建
- 不可变 Set:用
setOf()
函数,自动去重、无序; - 可变 Set:用
mutableSetOf()
函数,支持修改; - 若需 "有序 Set"(按插入顺序保存):用
LinkedHashSet
(创建方式linkedSetOf()
)。
示例:
Kotlin
// 1. 不可变 Set:重复元素被自动忽略,无序(输出顺序可能和插入顺序不同)
val colorSet: Set<String> = setOf("红色", "绿色", "红色", "蓝色")
println(colorSet) // 输出:[红色, 绿色, 蓝色](去重)
// 2. 可变 Set:支持添加/删除
val mutableColorSet: MutableSet<String> = mutableSetOf("红色", "绿色")
mutableColorSet.add("黄色")
mutableColorSet.remove("红色")
println(mutableColorSet) // 输出:[绿色, 黄色](无序)
// 3. 有序 Set(LinkedHashSet):按插入顺序保存,仍去重
val linkedColorSet: MutableSet<String> = linkedSetOf("红色", "绿色", "红色")
println(linkedColorSet) // 输出:[红色, 绿色](有序+去重)
(3)Map 的创建
Map 是 "键值对" 集合,每个元素包含 key
(键)和 value
(值),核心规则是 "键唯一,值可重复"。
- 不可变 Map:用
mapOf()
函数,键值对用to
关键字连接(如key to value
); - 可变 Map:用
mutableMapOf()
函数,支持put
/remove
等操作; - 有序 Map(按插入顺序):用
linkedMapOf()
函数。
示例:
Kotlin
// 1. 不可变 Map:键唯一,重复键会覆盖(后面的覆盖前面的)
val userMap: Map<String, Any> = mapOf(
"name" to "张三",
"age" to 20,
"gender" to "男",
"age" to 21 // 重复键,覆盖前面的 20
)
println(userMap) // 输出:{name=张三, age=21, gender=男}
// 2. 可变 Map:支持添加/修改/删除
val mutableUserMap: MutableMap<String, Any> = mutableMapOf(
"name" to "李四",
"age" to 18
)
mutableUserMap.put("gender", "女") // 添加键值对
mutableUserMap["age"] = 19 // 简化写法:修改值(等价于 put)
mutableUserMap.remove("gender") // 删除键值对
println(mutableUserMap) // 输出:{name=李四, age=19}
// 3. 有序 Map(LinkedHashMap):按插入顺序保存键值对
val linkedUserMap: MutableMap<String, Any> = linkedMapOf(
"name" to "王五",
"age" to 22
)
println(linkedUserMap) // 输出:{name=王五, age=22}(顺序与插入一致)
二、List 集合:有序、可重复的 "数据队列"
List 是最常用的集合类型,核心特性是元素有序(有固定索引,从 0 开始)、可重复,适合存储 "需要按顺序访问" 的数据(比如排行榜、待办清单)。
1. List 的核心特性回顾
- 有序:每个元素有唯一索引,可通过索引快速获取元素;
- 可重复:同一元素可多次添加,索引不同则视为不同位置的元素;
- 不可变 List(
List
):仅支持查询,无修改方法; - 可变 List(
MutableList
):支持添加、删除、修改元素。
2. List 的常用操作(附代码示例)
(1)获取元素:通过索引
不可变和可变 List 都支持,用 get(index)
方法或简化的 [index]
运算符(推荐后者,更简洁)。
Kotlin
val fruitList = listOf("苹果", "香蕉", "橙子")
// 方式1:get(index)
val firstFruit = fruitList.get(0)
// 方式2:[index](简化写法,推荐)
val secondFruit = fruitList[1]
println("第一个水果:$firstFruit,第二个水果:$secondFruit")
// 输出:第一个水果:苹果,第二个水果:香蕉
// 注意:索引越界会报错(比如访问 index=3,集合长度为 3,索引最大为 2)
// fruitList[3] // 抛出 IndexOutOfBoundsException
(2)添加元素:仅可变 List 支持
用 add(element)
追加到末尾,或 add(index, element)
插入到指定索引位置。
Kotlin
val mutableFruitList = mutableListOf("苹果", "香蕉")
// 1. 追加到末尾
mutableFruitList.add("葡萄")
// 2. 插入到索引 1 的位置(原索引 1 及之后的元素后移)
mutableFruitList.add(1, "橙子")
println(mutableFruitList) // 输出:[苹果, 橙子, 香蕉, 葡萄]
(3)删除元素:仅可变 List 支持
remove(element)
:根据元素值删除(删除第一个匹配的元素);removeAt(index)
:根据索引删除(更高效,直接定位);clear()
:清空所有元素。
Kotlin
val mutableFruitList = mutableListOf("苹果", "橙子", "香蕉", "葡萄")
// 1. 根据元素值删除
mutableFruitList.remove("橙子")
// 2. 根据索引删除(删除第三个元素,索引 2)
mutableFruitList.removeAt(2)
println(mutableFruitList) // 输出:[苹果, 香蕉]
// 3. 清空集合
mutableFruitList.clear()
println(mutableFruitList) // 输出:[]
(4)遍历元素:三种常用方式
- 普通
for
循环:通过索引遍历; for-in
循环:直接遍历元素(推荐,简洁);forEach
高阶函数:函数式遍历(更灵活,支持 lambda 逻辑)。
Kotlin
val fruitList = listOf("苹果", "香蕉", "橙子")
// 1. 普通 for 循环(通过索引)
for (i in 0 until fruitList.size) {
println("索引 $i:${fruitList[i]}")
}
// 2. for-in 循环(直接遍历元素)
for (fruit in fruitList) {
println("水果:$fruit")
}
// 3. forEach 高阶函数(lambda 表达式)
fruitList.forEach { fruit ->
println("forEach 遍历:$fruit")
}
// 简化:若 lambda 参数仅用一次,可用 it 代替
fruitList.forEach {
println("简化 forEach:$it")
}
(5)排序:sorted 系列方法
Kotlin 提供了丰富的排序 API,无需手动实现排序逻辑:
sorted()
:默认升序排序(适用于数值、字符串等可比较类型);sortedDescending()
:降序排序;sortedBy(selector)
:按指定属性排序(比如按对象的年龄、价格排序);sortedByDescending(selector)
:按指定属性降序排序。
示例(含普通数据和对象数据):
Kotlin
// 1. 数值 List 排序
val numList = listOf(3, 1, 4, 2)
val sortedAsc = numList.sorted() // 升序:[1, 2, 3, 4]
val sortedDesc = numList.sortedDescending() // 降序:[4, 3, 2, 1]
println("升序:$sortedAsc,降序:$sortedDesc")
// 2. 对象 List 排序(按属性)
data class Student(val name: String, val score: Int)
val studentList = listOf(
Student("张三", 85),
Student("李四", 92),
Student("王五", 78)
)
// 按分数升序排序
val sortedByScoreAsc = studentList.sortedBy { it.score }
// 按分数降序排序
val sortedByScoreDesc = studentList.sortedByDescending { it.score }
println("按分数升序:$sortedByScoreAsc")
// 输出:[Student(name=王五, score=78), Student(name=张三, score=85), Student(name=李四, score=92)]
(6)过滤:filter 方法
filter(predicate)
用于 "筛选符合条件的元素",参数是一个 lambda 表达式(返回布尔值,true
保留元素,false
过滤掉)。
示例:
Kotlin
// 1. 筛选偶数
val numList = listOf(1, 2, 3, 4, 5, 6)
val evenList = numList.filter { it % 2 == 0 }
println("偶数列表:$evenList") // 输出:[2, 4, 6]
// 2. 筛选长度大于 2 的字符串
val strList = listOf("a", "ab", "abc", "abcd")
val longStrList = strList.filter { it.length > 2 }
println("长度>2的字符串:$longStrList") // 输出:[abc, abcd]
// 3. 筛选分数>=80的学生
data class Student(val name: String, val score: Int)
val studentList = listOf(
Student("张三", 85),
Student("李四", 75),
Student("王五", 90)
)
val goodStudents = studentList.filter { it.score >= 80 }
println("分数>=80的学生:$goodStudents")
// 输出:[Student(name=张三, score=85), Student(name=王五, score=90)]
三、Set 集合:无序、不可重复的 "数据集合"
Set 适合存储 "需要去重" 的数据(比如用户 ID、标签列表),核心特性是无序(无索引,不能通过索引访问)、不可重复(添加重复元素会自动忽略) 。
1. Set 的核心特性回顾
- 无序:元素没有固定位置,遍历顺序可能与插入顺序不同(普通
HashSet
); - 不可重复:基于
equals()
和hashCode()
判断元素是否重复(若自定义对象,需重写这两个方法); - 不可变 Set(
Set
):仅支持查询,无修改方法; - 可变 Set(
MutableSet
):支持添加、删除元素。
2. Set 的常用操作(附代码示例)
(1)添加元素:仅可变 Set 支持
用 add(element)
方法,重复元素会自动忽略(无报错,返回 false
表示添加失败)。
Kotlin
val mutableTagSet = mutableSetOf("Kotlin", "Android", "Java")
// 1. 添加新元素(成功,返回 true)
val addSuccess = mutableTagSet.add("Jetpack")
// 2. 添加重复元素(失败,返回 false,集合无变化)
val addFail = mutableTagSet.add("Kotlin")
println(mutableTagSet) // 输出:[Kotlin, Android, Java, Jetpack](无序)
println("添加新元素成功?$addSuccess,添加重复元素成功?$addFail")
// 输出:添加新元素成功?true,添加重复元素成功?false
(2)判断元素是否存在:contains 方法
Set 的 contains(element)
方法效率极高(基于哈希表,时间复杂度 O (1)),适合频繁判断 "元素是否存在" 的场景。
Kotlin
val tagSet = setOf("Kotlin", "Android", "Java")
// 判断是否包含 "Android"
val hasAndroid = tagSet.contains("Android")
// 判断是否包含 "iOS"
val hasIos = tagSet.contains("iOS")
println("包含 Android?$hasAndroid,包含 iOS?$hasIos")
// 输出:包含 Android?true,包含 iOS?false
// 简化写法:用 in 关键字(等价于 contains)
val hasKotlin = "Kotlin" in tagSet
println("包含 Kotlin?$hasKotlin") // 输出:true
(3)集合运算:交集、并集、差集
Set 天然支持 "数学集合运算",Kotlin 直接提供了对应的 API,无需手动实现:
- 交集(
intersect
):两个集合的 "共有元素"; - 并集(
union
):两个集合的 "所有元素(去重)"; - 差集(
subtract
):当前集合 "减去另一个集合的元素后剩余的元素"。
示例:
Kotlin
val setA = setOf(1, 2, 3, 4)
val setB = setOf(3, 4, 5, 6)
// 1. 交集:共有的元素(3,4)
val intersection = setA.intersect(setB)
// 2. 并集:所有元素去重(1,2,3,4,5,6)
val union = setA.union(setB)
// 3. 差集:setA 减去 setB 的元素(1,2)
val subtract = setA.subtract(setB)
println("交集:$intersection,并集:$union,差集:$subtract")
// 输出:交集:[3, 4],并集:[1, 2, 3, 4, 5, 6],差集:[1, 2]
(4)遍历元素:仅支持 for-in 和 forEach
由于 Set 无序,没有索引,不能用 "普通 for 循环(索引遍历)",只能直接遍历元素:
Kotlin
val colorSet = setOf("红色", "绿色", "蓝色")
// 1. for-in 循环
for (color in colorSet) {
println("for-in 遍历:$color")
}
// 2. forEach 高阶函数
colorSet.forEach {
println("forEach 遍历:$it")
}
四、Map 集合:键值对、键唯一的 "数据字典"
Map 适合存储 "键值对应" 的数据(比如用户信息:id -> 用户对象
、配置项:key -> 配置值
),核心特性是键值对存储、键唯一(重复键会覆盖旧值)、值可重复。
1. Map 的核心特性回顾
- 键值对(key-value):每个元素由 "键" 和 "值" 组成,通过键获取值;
- 键唯一:同一 Map 中不能有重复键,重复
put
会覆盖旧值; - 值可重复:不同键可以对应相同的值;
- 不可变 Map(
Map
):仅支持查询,无修改方法; - 可变 Map(
MutableMap
):支持添加、修改、删除键值对。
2. Map 的常用操作(附代码示例)
(1)获取值:get 方法与 [] 运算符
get(key)
:根据键获取值,若键不存在,返回null
;[key]
:简化写法(等价于get(key)
);getOrDefault(key, defaultValue)
:键不存在时返回默认值(避免null
)。
示例:
Kotlin
val userMap = mapOf(
"name" to "张三",
"age" to 20,
"gender" to "男"
)
// 1. get(key) 方法
val name1 = userMap.get("name")
// 2. [] 简化写法(推荐)
val age1 = userMap["age"]
// 3. 键不存在,返回 null
val address1 = userMap["address"]
// 4. getOrDefault:键不存在时返回默认值
val address2 = userMap.getOrDefault("address", "未知地址")
println("姓名:$name1,年龄:$age1,地址1:$address1,地址2:$address2")
// 输出:姓名:张三,年龄:20,地址1:null,地址2:未知地址
(2)添加 / 修改键值对:仅可变 Map 支持
put(key, value)
:添加或修改键值对(键存在则修改,不存在则添加);[key] = value
:简化写法(等价于put
);putAll(fromMap)
:批量添加另一个 Map 的键值对。
示例:
Kotlin
val mutableUserMap = mutableMapOf(
"name" to "李四",
"age" to 18
)
// 1. 添加新键值对(address 不存在,添加)
mutableUserMap.put("address", "北京市")
// 2. 修改已有键值对(age 存在,修改为 19)
mutableUserMap["age"] = 19
// 3. 批量添加
val extraMap = mapOf("phone" to "13800138000", "email" to "lisi@example.com")
mutableUserMap.putAll(extraMap)
println(mutableUserMap)
// 输出:{name=李四, age=19, address=北京市, phone=13800138000, email=lisi@example.com}
(3)遍历元素:三种常用方式
Map 的遍历分为 "遍历键""遍历值""遍历键值对",按需选择:
Kotlin
val userMap = mapOf(
"name" to "张三",
"age" to 20,
"gender" to "男"
)
// 1. 遍历键(通过 keys 属性)
println("遍历键:")
for (key in userMap.keys) {
println("键:$key")
}
// 2. 遍历值(通过 values 属性)
println("遍历值:")
for (value in userMap.values) {
println("值:$value")
}
// 3. 遍历键值对(最常用)
println("遍历键值对:")
// 方式1:for-in 循环(解构赋值:将 key-value 拆分为两个变量)
for ((key, value) in userMap) {
println("$key: $value")
}
// 方式2:forEach 高阶函数(lambda 参数为 (key, value))
userMap.forEach { (key, value) ->
println("$key -> $value")
}
(4)判断键 / 值是否存在
containsKey(key)
:判断键是否存在;containsValue(value)
:判断值是否存在(效率低于containsKey
,因为需要遍历所有值)。
示例:
Kotlin
val userMap = mapOf(
"name" to "张三",
"age" to 20,
"gender" to "男"
)
// 判断键是否存在
val hasNameKey = userMap.containsKey("name")
val hasAddressKey = userMap.containsKey("address")
// 判断值是否存在
val hasAge20 = userMap.containsValue(20)
val hasAge30 = userMap.containsValue(30)
println("有 name 键?$hasNameKey,有 address 键?$hasAddressKey")
// 输出:有 name 键?true,有 address 键?false
println("有值 20?$hasAge20,有值 30?$hasAge30")
// 输出:有值 20?true,有值 30?false
五、集合的高阶函数操作:简化代码的 "神器"
Kotlin 集合框架的一大亮点是内置了大量高阶函数,可以用 "函数式编程" 的方式处理集合,大幅减少模板代码(比如无需手动写循环、判断)。本节课重点讲解最常用的 6 类高阶函数:转换、过滤、排序、聚合、分组、关联。
1. 转换:map 方法(将元素 "变形")
map(transform)
用于 "将集合中的每个元素按规则转换为新元素",返回一个新集合(元素类型可与原集合不同)。
示例(多种转换场景):
Kotlin
// 1. 数值转换:每个元素乘 2
val numList = listOf(1, 2, 3, 4)
val doubledList = numList.map { it * 2 }
println("数值乘 2:$doubledList") // 输出:[2, 4, 6, 8]
// 2. 字符串转换:每个字符串添加前缀
val strList = listOf("苹果", "香蕉", "橙子")
val prefixedList = strList.map { "水果:$it" }
println("添加前缀:$prefixedList") // 输出:[水果:苹果, 水果:香蕉, 水果:橙子]
// 3. 对象转换:提取对象的某个属性(常用!)
data class Student(val name: String, val score: Int)
val studentList = listOf(
Student("张三", 85),
Student("李四", 92),
Student("王五", 78)
)
// 提取所有学生的姓名,生成姓名列表
val nameList = studentList.map { it.name }
// 提取所有学生的分数,生成分数列表
val scoreList = studentList.map { it.score }
println("学生姓名列表:$nameList") // 输出:[张三, 李四, 王五]
println("学生分数列表:$scoreList") // 输出:[85, 92, 78]
2. 过滤:filter 系列方法(筛选元素)
除了前面讲过的 filter
(基础筛选),Kotlin 还提供了更细分的过滤方法,满足不同场景:
filterNot(predicate)
:反向筛选(保留false
的元素);filterIsInstance<T>()
:按类型筛选(保留指定类型的元素);filterNotNull()
:筛选非null
元素(适合可空类型集合)。
示例:
Kotlin
// 1. filterNot:反向筛选(保留偶数以外的元素)
val numList = listOf(1, 2, 3, 4, 5)
val oddList = numList.filterNot { it % 2 == 0 }
println("非偶数列表:$oddList") // 输出:[1, 3, 5]
// 2. filterIsInstance:按类型筛选(保留字符串元素)
val mixedList = listOf(1, "苹果", 3.14, "香蕉", true)
val stringList = mixedList.filterIsInstance<String>()
println("字符串列表:$stringList") // 输出:[苹果, 香蕉]
// 3. filterNotNull:筛选非 null 元素
val nullableList = listOf("张三", null, "李四", null, "王五")
val nonNullList = nullableList.filterNotNull()
println("非 null 列表:$nonNullList") // 输出:[张三, 李四, 王五]
3. 排序:sorted 系列方法(进阶)
除了前面讲过的基础排序,还有两个常用进阶排序方法:
sortedWith(comparator)
:自定义比较器排序(适合复杂排序逻辑);reversed()
:反转集合顺序(基于当前顺序反转)。
示例:
Kotlin
// 1. sortedWith:自定义比较器(按字符串长度排序)
val strList = listOf("apple", "banana", "cherry", "date")
// 按字符串长度升序排序(短的在前)
val sortedByLength = strList.sortedWith(compareBy { it.length })
println("按长度排序:$sortedByLength") // 输出:[date, apple, banana, cherry]
// 2. reversed:反转顺序
val numList = listOf(1, 2, 3, 4)
val reversedList = numList.reversed()
println("反转后:$reversedList") // 输出:[4, 3, 2, 1]
4. 聚合:count、sum、max、min(统计数据)
聚合函数用于 "对集合数据进行统计计算",返回单个结果值,常用的有:
count(predicate?)
:统计元素个数(可带条件,无条件则统计总个数);sumOf(selector)
:计算数值总和(推荐,支持 Int、Long、Double 等);maxOf(selector)
:获取最大值(按指定属性);minOf(selector)
:获取最小值(按指定属性);averageOf(selector)
:计算平均值(仅数值类型)。
示例:
Kotlin
data class Product(val name: String, val price: Double, val stock: Int)
val productList = listOf(
Product("手机", 2999.0, 50),
Product("平板", 1999.0, 30),
Product("耳机", 499.0, 100),
Product("手表", 1299.0, 20)
)
// 1. count:统计商品总数,及价格>1000的商品数
val totalCount = productList.count() // 总个数:4
val expensiveCount = productList.count { it.price > 1000 } // 价格>1000的个数:3
println("商品总数:$totalCount,高价商品数:$expensiveCount")
// 2. sum:计算总库存,及总金额(价格*库存)
val totalStock = productList.sumOf { it.stock } // 总库存:50+30+100+20=200
val totalAmount = productList.sumOf { it.price * it.stock } // 总金额
// 四舍五入(兼容写法)
val roundedAmount = Math.round(totalAmount).toLong()
println("总库存:$totalStock,总金额:$roundedAmount")
// 3. max/min:获取最高/最低价格(兼容旧版本)
val maxPrice = productList.maxOf { it.price } // 最高价格:2999.0
val minPrice = productList.minOf { it.price } // 最低价格:499.0
println("最高价格:$maxPrice,最低价格:$minPrice")
// 4. average:计算平均价格(兼容旧版本)
val avgPrice = productList.map { it.price }.average() // 先提取价格列表,再求平均
val roundedAvgPrice = avgPrice.toInt() // 简化:直接转为Int(自动截断小数)
println("平均价格:$roundedAvgPrice")
5. 分组:groupBy 方法(按条件分组)
groupBy(selector)
用于 "将集合按指定条件分组",返回一个 Map
:
- Map 的
key
:分组条件(selector lambda 的返回值); - Map 的
value
:该组的元素集合(与原集合元素类型相同)。
示例(常见分组场景):
Kotlin
// 1. 按性别分组(用户列表)
data class User(val name: String, val gender: String, val age: Int)
val userList = listOf(
User("张三", "男", 20),
User("李四", "女", 18),
User("王五", "男", 22),
User("赵六", "女", 19)
)
val groupedByGender = userList.groupBy { it.gender }
println("按性别分组:$groupedByGender")
// 输出:{男=[User(张三,男,20), User(王五,男,22)], 女=[User(李四,女,18), User(赵六,女,19)]}
// 2. 按分数段分组(学生列表)
data class Student(val name: String, val score: Int)
val studentList = listOf(
Student("张三", 85),
Student("李四", 92),
Student("王五", 78),
Student("赵六", 65),
Student("钱七", 59)
)
// 按分数段分组:"优秀"(>=90)、"良好"(80-89)、"及格"(60-79)、"不及格"(<60)
val groupedByScore = studentList.groupBy {
when {
it.score >= 90 -> "优秀"
it.score >= 80 -> "良好"
it.score >= 60 -> "及格"
else -> "不及格"
}
}
println("按分数段分组:$groupedByScore")
// 输出:{良好=[Student(张三,85)], 优秀=[Student(李四,92)], 及格=[Student(王五,78), Student(赵六,65)], 不及格=[Student(钱七,59)]}
6. 关联:associate 系列方法(生成 Map)
关联函数用于 "将集合转换为 Map",常用的有三个:
associate(transform)
:自定义键值对(transform 返回Pair<Key, Value>
);associateBy(selector)
:键为 selector 结果,值为原元素;associateWith(selector)
:键为原元素,值为 selector 结果。
示例:
Kotlin
data class Student(val id: Int, val name: String, val score: Int)
val studentList = listOf(
Student(1, "张三", 85),
Student(2, "李四", 92),
Student(3, "王五", 78)
)
// 1. associate:自定义键值对(id -> name)
val idToNameMap = studentList.associate { it.id to it.name }
println("id->name:$idToNameMap") // 输出:{1=张三, 2=李四, 3=王五}
// 2. associateBy:键为 id,值为 Student 对象(常用!通过 id 快速查对象)
val idToStudentMap = studentList.associateBy { it.id }
// 通过 id 获取 Student 对象
val student = idToStudentMap[2]
println("id=2 的学生:$student") // 输出:Student(id=2, name=李四, score=92)
// 3. associateWith:键为 Student 对象,值为 score
val studentToScoreMap = studentList.associateWith { it.score }
println("student->score:$studentToScoreMap")
// 输出:{Student(1,张三,85)=85, Student(2,李四,92)=92, Student(3,王五,78)=78}
六、集合的空安全与互操作性
1. 空安全:避免空指针
Kotlin 集合默认支持空安全,需注意:
- 不可变空集合:用
emptyList()
/emptySet()
/emptyMap()
(返回非空集合,只是元素为空); - 可空元素集合:声明时需指定类型为
List<T?>
(比如List<String?>
表示元素可空); - 过滤空元素:用
filterNotNull()
快速去除空元素(前面已讲)。
示例:
Kotlin
// 可空元素集合
val nullableStrList: List<String?> = listOf("苹果", null, "香蕉", null, "橙子")
// 过滤空元素,得到非空集合
val nonNullStrList: List<String> = nullableStrList.filterNotNull()
println(nonNullStrList) // 输出:[苹果, 香蕉, 橙子]
2. 与 Java 集合的互操作性
Kotlin 集合可以直接与 Java 集合互操作(无需手动转换):
- Kotlin 集合转 Java 集合:用
toJavaList()
/toJavaSet()
/toJavaMap()
(需导入kotlin.collections
); - Java 集合转 Kotlin 集合:直接赋值(Kotlin 会自动识别为
Mutable
集合)。
示例:
java
// Java 代码:返回一个 Java List
public class JavaCollectionUtils {
public static List<String> getJavaList() {
List<String> list = new ArrayList<>();
list.add("Java-苹果");
list.add("Java-香蕉");
return list;
}
}
Kotlin
// Kotlin 代码:使用 Java 集合
import com.example.JavaCollectionUtils
fun main() {
// Java List 转 Kotlin 集合(自动转为 MutableList)
val kotlinList: MutableList<String> = JavaCollectionUtils.getJavaList()
kotlinList.add("Kotlin-橙子")
println(kotlinList) // 输出:[Java-苹果, Java-香蕉, Kotlin-橙子]
// Kotlin 集合转 Java 集合
val kotlinSet = setOf("Kotlin-1", "Kotlin-2")
val javaSet: java.util.Set<String> = kotlinSet.toJavaSet()
}