在日常開發(fā)中,我們經(jīng)常需要處理 “一組數(shù)據(jù)”—— 比如學(xué)生列表、商品信息、用戶配置等。Kotlin 的集合框架就是專門用來管理和操作這些 “數(shù)據(jù)組” 的核心工具,它提供了一套簡潔、高效的 API,涵蓋了數(shù)據(jù)的存儲、查詢、過濾、排序等常見需求。本節(jié)課我們將從集合的分類開始,逐步深入講解 List、Set、Map 三大核心集合,以及能大幅簡化代碼的 “高階函數(shù)操作”。
一、集合的分類與初始化:先搞懂 “可變” 與 “不可變”
Kotlin 集合框架的核心特點(diǎn)是區(qū)分 “不可變集合” 和 “可變集合” —— 這是為了滿足 “數(shù)據(jù)安全性” 需求(比如避免誤修改全局?jǐn)?shù)據(jù))。兩者的本質(zhì)區(qū)別是:不可變集合創(chuàng)建后無法修改(不能添加、刪除元素),可變集合支持動態(tài)修改。
1. 三大集合類型的分類
Kotlin 主要提供三種核心集合類型,每種類型都對應(yīng) “不可變” 和 “可變” 兩個版本:
| 集合類型 | 不可變版本(只讀) | 可變版本(可讀寫) | 核心特性 |
|---|---|---|---|
| 列表 | List |
MutableList |
有序、可重復(fù)元素 |
| 集合 | Set |
MutableSet |
無序、不可重復(fù)元素 |
| 映射 | Map |
MutableMap |
鍵值對(key-value)、鍵唯一 |
2. 集合的創(chuàng)建方式:一行代碼搞定
Kotlin 提供了專門的 “工廠函數(shù)” 來創(chuàng)建集合,無需手動 new,語法簡潔。
(1)List 的創(chuàng)建
- 不可變 List:用
listOf()函數(shù),創(chuàng)建后無法修改; - 可變 List:用
mutableListOf()函數(shù),支持add/remove等操作; - 若需指定初始容量(優(yōu)化性能):用
mutableListOf(capacity)(比如mutableListOf(10)表示初始容量為 10)。
示例:
// 1. 不可變 List:元素按插入順序保存,可重復(fù)
val fruitList: List<String> = listOf("蘋果", "香蕉", "蘋果", "橙子")
// fruitList.add("葡萄") // 報錯:不可變集合沒有 add 方法
// 2. 可變 List:可動態(tài)修改
val mutableFruitList: MutableList<String> = mutableListOf("蘋果", "香蕉")
mutableFruitList.add("葡萄") // 添加元素
mutableFruitList.remove("香蕉") // 刪除元素
println(mutableFruitList) // 輸出:[蘋果, 葡萄]
// 3. 創(chuàng)建空 List(不可變空集合用 emptyList(),可變空集合用 mutableListOf())
val emptyImmutableList: List<Int> = emptyList()
val emptyMutableList: MutableList<Int> = mutableListOf()
(2)Set 的創(chuàng)建
- 不可變 Set:用
setOf()函數(shù),自動去重、無序; - 可變 Set:用
mutableSetOf()函數(shù),支持修改; - 若需 “有序 Set”(按插入順序保存):用
LinkedHashSet(創(chuàng)建方式linkedSetOf())。
示例:
// 1. 不可變 Set:重復(fù)元素被自動忽略,無序(輸出順序可能和插入順序不同)
val colorSet: Set<String> = setOf("紅色", "綠色", "紅色", "藍(lán)色")
println(colorSet) // 輸出:[紅色, 綠色, 藍(lán)色](去重)
// 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 的創(chuàng)建
Map 是 “鍵值對” 集合,每個元素包含 key(鍵)和 value(值),核心規(guī)則是 “鍵唯一,值可重復(fù)”。
- 不可變 Map:用
mapOf()函數(shù),鍵值對用to關(guān)鍵字連接(如key to value); - 可變 Map:用
mutableMapOf()函數(shù),支持put/remove等操作; - 有序 Map(按插入順序):用
linkedMapOf()函數(shù)。
示例:
// 1. 不可變 Map:鍵唯一,重復(fù)鍵會覆蓋(后面的覆蓋前面的)
val userMap: Map<String, Any> = mapOf(
"name" to "張三",
"age" to 20,
"gender" to "男",
"age" to 21 // 重復(fù)鍵,覆蓋前面的 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 集合:有序、可重復(fù)的 “數(shù)據(jù)隊列”
List 是最常用的集合類型,核心特性是元素有序(有固定索引,從 0 開始)、可重復(fù),適合存儲 “需要按順序訪問” 的數(shù)據(jù)(比如排行榜、待辦清單)。
1. List 的核心特性回顧
- 有序:每個元素有唯一索引,可通過索引快速獲取元素;
- 可重復(fù):同一元素可多次添加,索引不同則視為不同位置的元素;
- 不可變 List(
List):僅支持查詢,無修改方法; - 可變 List(
MutableList):支持添加、刪除、修改元素。
2. List 的常用操作(附代碼示例)
(1)獲取元素:通過索引
不可變和可變 List 都支持,用 get(index) 方法或簡化的 [index] 運(yùn)算符(推薦后者,更簡潔)。
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) 插入到指定索引位置。
val mutableFruitList = mutableListOf("蘋果", "香蕉")
// 1. 追加到末尾
mutableFruitList.add("葡萄")
// 2. 插入到索引 1 的位置(原索引 1 及之后的元素后移)
mutableFruitList.add(1, "橙子")
println(mutableFruitList) // 輸出:[蘋果, 橙子, 香蕉, 葡萄]
(3)刪除元素:僅可變 List 支持
-
remove(element):根據(jù)元素值刪除(刪除第一個匹配的元素); -
removeAt(index):根據(jù)索引刪除(更高效,直接定位); -
clear():清空所有元素。
val mutableFruitList = mutableListOf("蘋果", "橙子", "香蕉", "葡萄")
// 1. 根據(jù)元素值刪除
mutableFruitList.remove("橙子")
// 2. 根據(jù)索引刪除(刪除第三個元素,索引 2)
mutableFruitList.removeAt(2)
println(mutableFruitList) // 輸出:[蘋果, 香蕉]
// 3. 清空集合
mutableFruitList.clear()
println(mutableFruitList) // 輸出:[]
(4)遍歷元素:三種常用方式
- 普通
for循環(huán):通過索引遍歷; -
for-in循環(huán):直接遍歷元素(推薦,簡潔); -
forEach高階函數(shù):函數(shù)式遍歷(更靈活,支持 lambda 邏輯)。
val fruitList = listOf("蘋果", "香蕉", "橙子")
// 1. 普通 for 循環(huán)(通過索引)
for (i in 0 until fruitList.size) {
println("索引 $i:${fruitList[i]}")
}
// 2. for-in 循環(huán)(直接遍歷元素)
for (fruit in fruitList) {
println("水果:$fruit")
}
// 3. forEach 高階函數(shù)(lambda 表達(dá)式)
fruitList.forEach { fruit ->
println("forEach 遍歷:$fruit")
}
// 簡化:若 lambda 參數(shù)僅用一次,可用 it 代替
fruitList.forEach {
println("簡化 forEach:$it")
}
(5)排序:sorted 系列方法
Kotlin 提供了豐富的排序 API,無需手動實(shí)現(xiàn)排序邏輯:
-
sorted():默認(rèn)升序排序(適用于數(shù)值、字符串等可比較類型); -
sortedDescending():降序排序; -
sortedBy(selector):按指定屬性排序(比如按對象的年齡、價格排序); -
sortedByDescending(selector):按指定屬性降序排序。
示例(含普通數(shù)據(jù)和對象數(shù)據(jù)):
// 1. 數(shù)值 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)
)
// 按分?jǐn)?shù)升序排序
val sortedByScoreAsc = studentList.sortedBy { it.score }
// 按分?jǐn)?shù)降序排序
val sortedByScoreDesc = studentList.sortedByDescending { it.score }
println("按分?jǐn)?shù)升序:$sortedByScoreAsc")
// 輸出:[Student(name=王五, score=78), Student(name=張三, score=85), Student(name=李四, score=92)]
(6)過濾:filter 方法
filter(predicate) 用于 “篩選符合條件的元素”,參數(shù)是一個 lambda 表達(dá)式(返回布爾值,true 保留元素,false 過濾掉)。
示例:
// 1. 篩選偶數(shù)
val numList = listOf(1, 2, 3, 4, 5, 6)
val evenList = numList.filter { it % 2 == 0 }
println("偶數(shù)列表:$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. 篩選分?jǐn)?shù)>=80的學(xué)生
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("分?jǐn)?shù)>=80的學(xué)生:$goodStudents")
// 輸出:[Student(name=張三, score=85), Student(name=王五, score=90)]
三、Set 集合:無序、不可重復(fù)的 “數(shù)據(jù)集合”
Set 適合存儲 “需要去重” 的數(shù)據(jù)(比如用戶 ID、標(biāo)簽列表),核心特性是無序(無索引,不能通過索引訪問)、不可重復(fù)(添加重復(fù)元素會自動忽略) 。
1. Set 的核心特性回顧
- 無序:元素沒有固定位置,遍歷順序可能與插入順序不同(普通
HashSet); - 不可重復(fù):基于
equals()和hashCode()判斷元素是否重復(fù)(若自定義對象,需重寫這兩個方法); - 不可變 Set(
Set):僅支持查詢,無修改方法; - 可變 Set(
MutableSet):支持添加、刪除元素。
2. Set 的常用操作(附代碼示例)
(1)添加元素:僅可變 Set 支持
用 add(element) 方法,重復(fù)元素會自動忽略(無報錯,返回 false 表示添加失?。?。
val mutableTagSet = mutableSetOf("Kotlin", "Android", "Java")
// 1. 添加新元素(成功,返回 true)
val addSuccess = mutableTagSet.add("Jetpack")
// 2. 添加重復(fù)元素(失敗,返回 false,集合無變化)
val addFail = mutableTagSet.add("Kotlin")
println(mutableTagSet) // 輸出:[Kotlin, Android, Java, Jetpack](無序)
println("添加新元素成功?$addSuccess,添加重復(fù)元素成功?$addFail")
// 輸出:添加新元素成功?true,添加重復(fù)元素成功?false
(2)判斷元素是否存在:contains 方法
Set 的 contains(element) 方法效率極高(基于哈希表,時間復(fù)雜度 O (1)),適合頻繁判斷 “元素是否存在” 的場景。
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 關(guān)鍵字(等價于 contains)
val hasKotlin = "Kotlin" in tagSet
println("包含 Kotlin?$hasKotlin") // 輸出:true
(3)集合運(yùn)算:交集、并集、差集
Set 天然支持 “數(shù)學(xué)集合運(yùn)算”,Kotlin 直接提供了對應(yīng)的 API,無需手動實(shí)現(xiàn):
- 交集(
intersect):兩個集合的 “共有元素”; - 并集(
union):兩個集合的 “所有元素(去重)”; - 差集(
subtract):當(dāng)前集合 “減去另一個集合的元素后剩余的元素”。
示例:
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 循環(huán)(索引遍歷)”,只能直接遍歷元素:
val colorSet = setOf("紅色", "綠色", "藍(lán)色")
// 1. for-in 循環(huán)
for (color in colorSet) {
println("for-in 遍歷:$color")
}
// 2. forEach 高階函數(shù)
colorSet.forEach {
println("forEach 遍歷:$it")
}
四、Map 集合:鍵值對、鍵唯一的 “數(shù)據(jù)字典”
Map 適合存儲 “鍵值對應(yīng)” 的數(shù)據(jù)(比如用戶信息:id -> 用戶對象、配置項:key -> 配置值),核心特性是鍵值對存儲、鍵唯一(重復(fù)鍵會覆蓋舊值)、值可重復(fù)。
1. Map 的核心特性回顧
- 鍵值對(key-value):每個元素由 “鍵” 和 “值” 組成,通過鍵獲取值;
- 鍵唯一:同一 Map 中不能有重復(fù)鍵,重復(fù)
put會覆蓋舊值; - 值可重復(fù):不同鍵可以對應(yīng)相同的值;
- 不可變 Map(
Map):僅支持查詢,無修改方法; - 可變 Map(
MutableMap):支持添加、修改、刪除鍵值對。
2. Map 的常用操作(附代碼示例)
(1)獲取值:get 方法與 [] 運(yùn)算符
-
get(key):根據(jù)鍵獲取值,若鍵不存在,返回null; -
[key]:簡化寫法(等價于get(key)); -
getOrDefault(key, defaultValue):鍵不存在時返回默認(rèn)值(避免null)。
示例:
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:鍵不存在時返回默認(rèn)值
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 的鍵值對。
示例:
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 的遍歷分為 “遍歷鍵”“遍歷值”“遍歷鍵值對”,按需選擇:
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 循環(huán)(解構(gòu)賦值:將 key-value 拆分為兩個變量)
for ((key, value) in userMap) {
println("$key: $value")
}
// 方式2:forEach 高階函數(shù)(lambda 參數(shù)為 (key, value))
userMap.forEach { (key, value) ->
println("$key -> $value")
}
(4)判斷鍵 / 值是否存在
-
containsKey(key):判斷鍵是否存在; -
containsValue(value):判斷值是否存在(效率低于containsKey,因為需要遍歷所有值)。
示例:
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
五、集合的高階函數(shù)操作:簡化代碼的 “神器”
Kotlin 集合框架的一大亮點(diǎn)是內(nèi)置了大量高階函數(shù),可以用 “函數(shù)式編程” 的方式處理集合,大幅減少模板代碼(比如無需手動寫循環(huán)、判斷)。本節(jié)課重點(diǎn)講解最常用的 6 類高階函數(shù):轉(zhuǎn)換、過濾、排序、聚合、分組、關(guān)聯(lián)。
1. 轉(zhuǎn)換:map 方法(將元素 “變形”)
map(transform) 用于 “將集合中的每個元素按規(guī)則轉(zhuǎn)換為新元素”,返回一個新集合(元素類型可與原集合不同)。
示例(多種轉(zhuǎn)換場景):
// 1. 數(shù)值轉(zhuǎn)換:每個元素乘 2
val numList = listOf(1, 2, 3, 4)
val doubledList = numList.map { it * 2 }
println("數(shù)值乘 2:$doubledList") // 輸出:[2, 4, 6, 8]
// 2. 字符串轉(zhuǎn)換:每個字符串添加前綴
val strList = listOf("蘋果", "香蕉", "橙子")
val prefixedList = strList.map { "水果:$it" }
println("添加前綴:$prefixedList") // 輸出:[水果:蘋果, 水果:香蕉, 水果:橙子]
// 3. 對象轉(zhuǎn)換:提取對象的某個屬性(常用?。?data class Student(val name: String, val score: Int)
val studentList = listOf(
Student("張三", 85),
Student("李四", 92),
Student("王五", 78)
)
// 提取所有學(xué)生的姓名,生成姓名列表
val nameList = studentList.map { it.name }
// 提取所有學(xué)生的分?jǐn)?shù),生成分?jǐn)?shù)列表
val scoreList = studentList.map { it.score }
println("學(xué)生姓名列表:$nameList") // 輸出:[張三, 李四, 王五]
println("學(xué)生分?jǐn)?shù)列表:$scoreList") // 輸出:[85, 92, 78]
2. 過濾:filter 系列方法(篩選元素)
除了前面講過的 filter(基礎(chǔ)篩選),Kotlin 還提供了更細(xì)分的過濾方法,滿足不同場景:
-
filterNot(predicate):反向篩選(保留false的元素); -
filterIsInstance<T>():按類型篩選(保留指定類型的元素); -
filterNotNull():篩選非null元素(適合可空類型集合)。
示例:
// 1. filterNot:反向篩選(保留偶數(shù)以外的元素)
val numList = listOf(1, 2, 3, 4, 5)
val oddList = numList.filterNot { it % 2 == 0 }
println("非偶數(shù)列表:$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 系列方法(進(jìn)階)
除了前面講過的基礎(chǔ)排序,還有兩個常用進(jìn)階排序方法:
-
sortedWith(comparator):自定義比較器排序(適合復(fù)雜排序邏輯); -
reversed():反轉(zhuǎn)集合順序(基于當(dāng)前順序反轉(zhuǎn))。
示例:
// 1. sortedWith:自定義比較器(按字符串長度排序)
val strList = listOf("apple", "banana", "cherry", "date")
// 按字符串長度升序排序(短的在前)
val sortedByLength = strList.sortedWith(compareBy { it.length })
println("按長度排序:$sortedByLength") // 輸出:[date, apple, banana, cherry]
// 2. reversed:反轉(zhuǎn)順序
val numList = listOf(1, 2, 3, 4)
val reversedList = numList.reversed()
println("反轉(zhuǎn)后:$reversedList") // 輸出:[4, 3, 2, 1]
4. 聚合:count、sum、max、min(統(tǒng)計數(shù)據(jù))
聚合函數(shù)用于 “對集合數(shù)據(jù)進(jìn)行統(tǒng)計計算”,返回單個結(jié)果值,常用的有:
-
count(predicate?):統(tǒng)計元素個數(shù)(可帶條件,無條件則統(tǒng)計總個數(shù)); -
sumOf(selector):計算數(shù)值總和(推薦,支持 Int、Long、Double 等); -
maxOf(selector):獲取最大值(按指定屬性); -
minOf(selector):獲取最小值(按指定屬性); -
averageOf(selector):計算平均值(僅數(shù)值類型)。
示例:
data class Product(val name: String, val price: Double, val stock: Int)
val productList = listOf(
Product("手機(jī)", 2999.0, 50),
Product("平板", 1999.0, 30),
Product("耳機(jī)", 499.0, 100),
Product("手表", 1299.0, 20)
)
// 1. count:統(tǒng)計商品總數(shù),及價格>1000的商品數(shù)
val totalCount = productList.count() // 總個數(shù):4
val expensiveCount = productList.count { it.price > 1000 } // 價格>1000的個數(shù):3
println("商品總數(shù):$totalCount,高價商品數(shù):$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() // 簡化:直接轉(zhuǎn)為Int(自動截斷小數(shù))
println("平均價格:$roundedAvgPrice")
5. 分組:groupBy 方法(按條件分組)
groupBy(selector) 用于 “將集合按指定條件分組”,返回一個 Map:
- Map 的
key:分組條件(selector lambda 的返回值); - Map 的
value:該組的元素集合(與原集合元素類型相同)。
示例(常見分組場景):
// 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. 按分?jǐn)?shù)段分組(學(xué)生列表)
data class Student(val name: String, val score: Int)
val studentList = listOf(
Student("張三", 85),
Student("李四", 92),
Student("王五", 78),
Student("趙六", 65),
Student("錢七", 59)
)
// 按分?jǐn)?shù)段分組:"優(yōu)秀"(>=90)、"良好"(80-89)、"及格"(60-79)、"不及格"(<60)
val groupedByScore = studentList.groupBy {
when {
it.score >= 90 -> "優(yōu)秀"
it.score >= 80 -> "良好"
it.score >= 60 -> "及格"
else -> "不及格"
}
}
println("按分?jǐn)?shù)段分組:$groupedByScore")
// 輸出:{良好=[Student(張三,85)], 優(yōu)秀=[Student(李四,92)], 及格=[Student(王五,78), Student(趙六,65)], 不及格=[Student(錢七,59)]}
6. 關(guān)聯(lián):associate 系列方法(生成 Map)
關(guān)聯(lián)函數(shù)用于 “將集合轉(zhuǎn)換為 Map”,常用的有三個:
-
associate(transform):自定義鍵值對(transform 返回Pair<Key, Value>); -
associateBy(selector):鍵為 selector 結(jié)果,值為原元素; -
associateWith(selector):鍵為原元素,值為 selector 結(jié)果。
示例:
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 的學(xué)生:$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 集合默認(rèn)支持空安全,需注意:
- 不可變空集合:用
emptyList()/emptySet()/emptyMap()(返回非空集合,只是元素為空); - 可空元素集合:聲明時需指定類型為
List<T?>(比如List<String?>表示元素可空); - 過濾空元素:用
filterNotNull()快速去除空元素(前面已講)。
示例:
// 可空元素集合
val nullableStrList: List<String?> = listOf("蘋果", null, "香蕉", null, "橙子")
// 過濾空元素,得到非空集合
val nonNullStrList: List<String> = nullableStrList.filterNotNull()
println(nonNullStrList) // 輸出:[蘋果, 香蕉, 橙子]
2. 與 Java 集合的互操作性
Kotlin 集合可以直接與 Java 集合互操作(無需手動轉(zhuǎn)換):
- Kotlin 集合轉(zhuǎn) Java 集合:用
toJavaList()/toJavaSet()/toJavaMap()(需導(dǎo)入kotlin.collections); - Java 集合轉(zhuǎn) Kotlin 集合:直接賦值(Kotlin 會自動識別為
Mutable集合)。
示例:
// 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 代碼:使用 Java 集合
import com.example.JavaCollectionUtils
fun main() {
// Java List 轉(zhuǎn) Kotlin 集合(自動轉(zhuǎn)為 MutableList)
val kotlinList: MutableList<String> = JavaCollectionUtils.getJavaList()
kotlinList.add("Kotlin-橙子")
println(kotlinList) // 輸出:[Java-蘋果, Java-香蕉, Kotlin-橙子]
// Kotlin 集合轉(zhuǎn) Java 集合
val kotlinSet = setOf("Kotlin-1", "Kotlin-2")
val javaSet: java.util.Set<String> = kotlinSet.toJavaSet()
}