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 小时前
Gateway-过滤器
java·分布式·spring·spring cloud·微服务·gateway·sentinel
hssfscv3 小时前
JAVA学习笔记——9道综合练习习题+二维数组
java·笔记·学习
初听于你5 小时前
缓存技术揭秘
java·运维·服务器·开发语言·spring·缓存
小蒜学长6 小时前
springboot多功能智能手机阅读APP设计与实现(代码+数据库+LW)
java·spring boot·后端·智能手机
奥尔特星云大使7 小时前
MySQL 慢查询日志slow query log
android·数据库·mysql·adb·慢日志·slow query log
zizisuo8 小时前
解决在使用Lombok时maven install 找不到符号的问题
java·数据库·maven
笨蛋少年派9 小时前
JAVA基础语法
java·开发语言
Haooog9 小时前
654.最大二叉树(二叉树算法)
java·数据结构·算法·leetcode·二叉树
我真的是大笨蛋9 小时前
依赖倒置原则(DIP)
java·设计模式·性能优化·依赖倒置原则·设计规范
东方芷兰10 小时前
JavaWeb 课堂笔记 —— 20 SpringBootWeb案例 配置文件
java·开发语言·笔记·算法·log4j·intellij-idea·lua