Kotlin学习第 6 课:Kotlin 集合框架:操作数据的核心工具

在日常开发中,我们经常需要处理 "一组数据"------ 比如学生列表、商品信息、用户配置等。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()
}
相关推荐
叽哥2 小时前
Kotlin学习第 5 课:Kotlin 面向对象编程:类、对象与继承
android·java·kotlin
心月狐的流火号2 小时前
Spring Bean 生命周期详解——简单、清晰、全面、实用
java·spring
little_xianzhong2 小时前
步骤流程中日志记录方案(类aop)
java·开发语言
半桔3 小时前
【STL源码剖析】二叉世界的平衡:从BST 到 AVL-tree 和 RB-tree 的插入逻辑
java·数据结构·c++·算法·set·map
用户3721574261353 小时前
Python 轻松实现替换或修改 PDF 文字
java
用户6083089290473 小时前
Java中的接口(Interface)与抽象类(Abstract Class)
java·后端
大白的编程日记.3 小时前
【MySQL】表的操作和数据类型
android·数据库·mysql
前行的小黑炭3 小时前
Android LayoutInflater 是什么?XML到View的过程
android·java·kotlin
尚久龙3 小时前
安卓学习 之 SeekBar(音视频播放进度条)
android·java·学习·手机·android studio