KMP 实现鸿蒙跨端:Kotlin 集合操作和数据处理指南
Kotlin Multiplatform (KMP) 实现鸿蒙跨端应用中的集合操作和数据处理,通过 Kotlin 强大的集合框架提供高效的数据处理能力。文档介绍了 List、Set、Map 三种核心集合类型及其操作方法,展示了如何将 Kotlin 代码编译为 JavaScript 并在 ArkTS 应用中调用。重点包括:创建不可变/可变集合、基础操作(如过滤、映射、排序)、高级操作(分组、分区)以
目录
概述
本文档介绍如何使用 Kotlin Multiplatform (KMP) 实现鸿蒙跨端应用中的集合操作和数据处理。Kotlin 提供了强大而灵活的集合框架,使得数据处理变得简洁而高效。通过 KMP,我们可以编写一份 Kotlin 代码,将其编译到 JavaScript,在 OpenHarmony ArkTS 应用中调用,实现真正的跨端代码复用。
为什么需要学习集合操作?
- 数据处理:大多数应用都需要处理多个数据项
- 代码简洁性:Kotlin 的集合 API 使代码更加简洁易读
- 性能优化:正确使用集合可以提高应用性能
- 跨端编译:集合操作在编译到 JavaScript 时表现良好,完美支持 OpenHarmony 应用
- 代码复用:一份 Kotlin 代码可同时服务多个平台(Web、移动端等)
集合类型
Kotlin 提供了三种主要的集合接口:
1. List(列表)
有序集合,允许重复元素。
// 不可变列表
val immutableList = listOf(1, 2, 3, 4, 5)
// 可变列表
val mutableList = mutableListOf(1, 2, 3)
mutableList.add(4)
mutableList.remove(1)
这段代码演示了如何创建和操作列表。使用 listOf() 创建一个不可变列表,包含 5 个整数。不可变列表创建后不能修改,提供了更好的线程安全性。使用 mutableListOf() 创建一个可变列表,初始包含 3 个元素。使用 add() 方法添加元素 4,列表变为 [1, 2, 3, 4]。使用 remove() 方法删除元素 1,列表变为 [2, 3, 4]。列表是有序的,支持按索引访问,允许重复元素。
特点:
- 有序存储
- 支持按索引访问
- 允许重复元素
- 性能优良
2. Set(集合)
无序集合,不允许重复元素。
// 不可变集合
val immutableSet = setOf("Apple", "Banana", "Cherry")
// 可变集合
val mutableSet = mutableSetOf("A", "B", "C")
mutableSet.add("D")
这段代码演示了如何创建和操作集合。使用 setOf() 创建一个不可变集合,包含 3 个字符串。集合是无序的,不允许重复元素。使用 mutableSetOf() 创建一个可变集合,初始包含 3 个元素。使用 add() 方法添加元素 “D”,集合变为 {“A”, “B”, “C”, “D”}。集合的主要优势是快速查找和自动去重。
特点:
- 无序存储
- 不允许重复
- 快速查找
- 自动去重
3. Map(映射)
键值对集合,每个键对应一个值。
// 不可变映射
val immutableMap = mapOf("name" to "Kotlin", "version" to "1.9")
// 可变映射
val mutableMap = mutableMapOf("key1" to "value1")
mutableMap["key2"] = "value2"
这段代码演示了如何创建和操作映射。使用 mapOf() 创建一个不可变映射,使用 to 关键字定义键值对。不可变映射创建后不能修改。使用 mutableMapOf() 创建一个可变映射,初始包含一个键值对。使用方括号 [] 语法添加新的键值对 “key2” -> “value2”。映射提供了快速的键值查找,键必须唯一,值可以重复。
特点:
- 键值对存储
- 快速查找
- 键唯一,值可重复
- 灵活的数据组织
基础操作
创建集合
Kotlin 源代码
@OptIn(ExperimentalJsExport::class)
@JsExport
fun listExample(): String {
val fruits = listOf("Apple", "Banana", "Cherry", "Date")
val numbers = listOf(1, 2, 3, 4, 5)
val fruitsStr = fruits.joinToString(", ")
val sum = numbers.sum()
val average = numbers.average()
val result = "Fruits: $fruitsStr\nNumbers: ${numbers.joinToString(", ")}\nSum: $sum\nAverage: $average"
println(result)
return result
}
这是列表操作的核心实现函数,展示了基本的列表操作。函数使用 @OptIn(ExperimentalJsExport::class) 和 @JsExport 注解,使其可以被编译成 JavaScript 并在 ArkTS 中调用。创建一个水果列表和一个数字列表。使用 joinToString() 将水果列表转换为逗号分隔的字符串。使用 sum() 计算数字列表的总和。使用 average() 计算数字列表的平均值。使用字符串模板格式化输出结果。这个函数展示了如何将列表操作转换为用户友好的输出。
编译后的 JavaScript 代码
function listExample() {
var fruits = listOf(['Apple', 'Banana', 'Cherry', 'Date']);
var numbers = listOf([1, 2, 3, 4, 5]);
var fruitsStr = joinToString_0(fruits, ', ');
var sum_0 = sum(numbers);
var average_0 = average(numbers);
var result = 'Fruits: ' + fruitsStr + '\nNumbers: ' + joinToString_0(numbers, ', ') + '\nSum: ' + sum_0 + '\nAverage: ' + average_0;
println(result);
return result;
}
这段代码是 Kotlin 编译器生成的 JavaScript 代码,展示了 Kotlin 列表操作如何被转换为 JavaScript。listOf() 函数创建一个列表。joinToString_0() 函数将列表转换为字符串。sum() 函数计算数字列表的总和。average_0() 函数计算平均值。使用字符串连接操作符 + 拼接结果。println() 函数输出结果。这个编译过程展示了 KMP 如何将高级的 Kotlin 列表操作转换为高效的 JavaScript 代码。
ArkTS 调用代码
import { listExample } from './hellokjs';
@Entry
@Component
struct Index {
@State message: string = '加载中...';
@State results: string[] = [];
aboutToAppear(): void {
this.loadResults();
}
loadResults(): void {
try {
// 调用 Kotlin 编译的 JavaScript 函数
const listResult = listExample();
this.results = [listResult];
this.message = '案例已加载';
} catch (error) {
this.message = `错误: ${error}`;
}
}
build() {
Column() {
Text('Kotlin List 操作案例演示')
.fontSize(24)
.fontWeight(FontWeight.Bold)
.margin({ top: 20, bottom: 20 })
Text(this.message)
.fontSize(14)
.fontColor(Color.Gray)
.margin({ bottom: 15 })
Scroll() {
Column() {
ForEach(this.results, (result: string) => {
Text(result)
.fontSize(12)
.fontFamily('monospace')
.padding(12)
.width('100%')
.backgroundColor(Color.White)
.border({ width: 1, color: Color.Gray })
.borderRadius(8)
})
}
.width('100%')
.padding({ left: 15, right: 15 })
}
.layoutWeight(1)
.width('100%')
Button('刷新结果')
.width('80%')
.height(40)
.margin({ bottom: 20 })
.onClick(() => {
this.loadResults();
})
}
.width('100%')
.height('100%')
.backgroundColor('#f5f5f5')
}
}
这段 ArkTS 代码是鸿蒙应用的用户界面实现,展示了如何在 ArkTS 中导入和调用编译后的 Kotlin 函数。首先使用 import 语句从编译后的 JavaScript 模块中导入 listExample 函数。使用 @State 装饰器定义两个响应式状态变量:message 用于显示状态信息,results 存储列表操作的结果。aboutToAppear() 生命周期函数在组件加载时自动调用 loadResults() 进行初始化。loadResults() 方法调用 Kotlin 编译的 JavaScript 函数 listExample(),获取列表操作结果,然后更新 results 和 message。使用 try-catch 块捕获异常。build() 方法构建整个 UI 布局,包含标题、状态信息、可滚动的结果显示区域和刷新按钮。使用 ForEach 遍历 results 数组,为每个结果创建一个 Text 组件。这个结构实现了清晰的前后端职责划分:ArkTS 只负责收集输入和展示结果,所有列表操作逻辑都集中在 Kotlin 中。
其他集合创建方式
// Set 创建
val set1 = setOf("a", "b", "c") // 不可变
val set2 = mutableSetOf("a", "b", "c") // 可变
// Map 创建
val map1 = mapOf("a" to 1, "b" to 2) // 不可变
val map2 = mutableMapOf("a" to 1, "b" to 2) // 可变
这段代码展示了如何创建 Set 和 Map 集合。使用 setOf() 创建不可变集合,包含三个字符串元素。使用 mutableSetOf() 创建可变集合,允许后续添加或删除元素。使用 mapOf() 创建不可变映射,使用 to 关键字定义键值对。使用 mutableMapOf() 创建可变映射,允许后续修改键值对。不可变集合和映射提供了更好的线程安全性和编译器优化机会。
访问元素
val list = listOf(10, 20, 30, 40, 50)
// 按索引访问
val first = list[0] // 10
val last = list.last() // 50
// 条件访问
val firstEven = list.firstOrNull { it % 2 == 0 } // 10
这段代码展示了如何访问列表中的元素。使用方括号 [] 按索引访问元素,list[0] 获取第一个元素 10。使用 last() 方法获取最后一个元素 50。使用 firstOrNull() 方法根据条件查找第一个满足条件的元素,如果找到返回该元素,否则返回 null。这里查找第一个偶数,返回 10。列表支持多种访问方式,可以按索引访问,也可以根据条件查找。
修改集合
val list = mutableListOf(1, 2, 3)
// 添加元素
list.add(4) // [1, 2, 3, 4]
list.addAll(listOf(5, 6)) // [1, 2, 3, 4, 5, 6]
// 删除元素
list.remove(2) // [1, 3, 4, 5, 6]
list.removeAt(0) // [3, 4, 5, 6]
// 修改元素
list[0] = 10 // [10, 4, 5, 6]
这段代码展示了如何修改可变列表。使用 add() 方法添加单个元素 4 到列表末尾。使用 addAll() 方法添加多个元素 [5, 6] 到列表末尾。使用 remove() 方法删除指定值的元素,删除值为 2 的元素。使用 removeAt() 方法删除指定索引的元素,删除索引 0 处的元素。使用方括号 [] 语法修改指定索引的元素,将索引 0 处的元素修改为 10。可变列表提供了灵活的修改操作,可以添加、删除和修改元素。
高级操作
1. 映射(Map)
将集合中的每个元素转换为另一种形式。
Kotlin 源代码
@OptIn(ExperimentalJsExport::class)
@JsExport
fun mapExample(): String {
val numbers = listOf(1, 2, 3, 4, 5)
// 将每个数字乘以 2
val doubled = numbers.map { it * 2 }
// 将数字转换为字符串
val strings = numbers.map { "数字: $it" }
val result = "原始数据: ${numbers.joinToString(", ")}\n" +
"翻倍结果: ${doubled.joinToString(", ")}\n" +
"字符串转换: ${strings.joinToString(", ")}"
println(result)
return result
}
这是映射操作的核心实现函数,展示了如何转换集合中的元素。函数使用 @OptIn(ExperimentalJsExport::class) 和 @JsExport 注解,使其可以被编译成 JavaScript 并在 ArkTS 中调用。创建一个包含 1 到 5 的数字列表。使用 map() 函数将每个数字乘以 2,生成 [2, 4, 6, 8, 10]。使用 map() 函数将每个数字转换为字符串,生成 [“数字: 1”, “数字: 2”, …]。使用字符串模板和 joinToString() 格式化输出结果。这个函数展示了如何将映射操作转换为用户友好的输出。
编译后的 JavaScript 代码
function mapExample() {
var numbers = listOf([1, 2, 3, 4, 5]);
// 将每个数字乘以 2
var destination = ArrayList_init_$Create$_0(collectionSizeOrDefault(numbers, 10));
var _iterator__ex2g4s = numbers.b();
while (_iterator__ex2g4s.c()) {
var item = _iterator__ex2g4s.d();
var tmp$ret$0 = imul_0(item, 2);
destination.t(tmp$ret$0);
}
var doubled = destination;
// 将数字转换为字符串
var destination_0 = ArrayList_init_$Create$_0(collectionSizeOrDefault(numbers, 10));
var _iterator__ex2g4s_0 = numbers.b();
while (_iterator__ex2g4s_0.c()) {
var item_0 = _iterator__ex2g4s_0.d();
var tmp$ret$3 = '数字: ' + item_0;
destination_0.t(tmp$ret$3);
}
var strings = destination_0;
var result = '原始数据: ' + joinToString_0(numbers, ', ') + '\n' +
('翻倍结果: ' + joinToString_0(doubled, ', ') + '\n') +
('字符串转换: ' + joinToString_0(strings, ', '));
println(result);
return result;
}
这段代码是 Kotlin 编译器生成的 JavaScript 代码,展示了 Kotlin 映射操作如何被转换为 JavaScript。ArrayList_init_$Create$_0() 创建一个临时的 ArrayList 用于存储映射结果。collectionSizeOrDefault() 预分配足够的空间。numbers.b() 获取列表的迭代器。while 循环遍历集合中的每个元素。imul_0() 执行乘法操作。destination.t() 将转换后的元素添加到结果列表。映射操作被转换为显式的循环和数组操作。这个编译过程展示了 KMP 如何将高级的 Kotlin 映射操作转换为高效的 JavaScript 代码。
ArkTS 调用代码
import { mapExample } from './hellokjs';
@Entry
@Component
struct Index {
@State message: string = '加载中...';
@State results: string[] = [];
aboutToAppear(): void {
this.loadResults();
}
loadResults(): void {
try {
// 调用 Kotlin 编译的 JavaScript 函数
const mapResult = mapExample();
this.results = [mapResult];
this.message = '案例已加载';
} catch (error) {
this.message = `错误: ${error}`;
}
}
build() {
Column() {
Text('Kotlin Map 操作案例演示')
.fontSize(24)
.fontWeight(FontWeight.Bold)
.margin({ top: 20, bottom: 20 })
Text(this.message)
.fontSize(14)
.fontColor(Color.Gray)
.margin({ bottom: 15 })
Scroll() {
Column() {
ForEach(this.results, (result: string) => {
Text(result)
.fontSize(12)
.fontFamily('monospace')
.padding(12)
.width('100%')
.backgroundColor(Color.White)
.border({ width: 1, color: Color.Gray })
.borderRadius(8)
})
}
.width('100%')
.padding({ left: 15, right: 15 })
}
.layoutWeight(1)
.width('100%')
Button('刷新结果')
.width('80%')
.height(40)
.margin({ bottom: 20 })
.onClick(() => {
this.loadResults();
})
}
.width('100%')
.height('100%')
.backgroundColor('#f5f5f5')
}
}
这段 ArkTS 代码是鸿蒙应用的用户界面实现,展示了如何在 ArkTS 中导入和调用编译后的 Kotlin 映射函数。首先使用 import 语句从编译后的 JavaScript 模块中导入 mapExample 函数。使用 @State 装饰器定义两个响应式状态变量:message 用于显示状态信息,results 存储映射操作的结果。aboutToAppear() 生命周期函数在组件加载时自动调用 loadResults() 进行初始化。loadResults() 方法调用 Kotlin 编译的 JavaScript 函数 mapExample(),获取映射操作结果,然后更新 results 和 message。使用 try-catch 块捕获异常。build() 方法构建整个 UI 布局,包含标题、状态信息、可滚动的结果显示区域和刷新按钮。这个结构实现了清晰的前后端职责划分:ArkTS 只负责展示结果,所有映射操作逻辑都集中在 Kotlin 中。
2. 过滤(Filter)
根据条件筛选元素。
@OptIn(ExperimentalJsExport::class)
@JsExport
fun filterExample(): String {
val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
// 筛选偶数
val evens = numbers.filter { it % 2 == 0 }
// 筛选大于 5 的数字
val greaterThan5 = numbers.filter { it > 5 }
val result = "Original: ${numbers.joinToString(", ")}\n" +
"Evens: ${evens.joinToString(", ")}\n" +
"Greater than 5: ${greaterThan5.joinToString(", ")}"
println(result)
return result
}
这是过滤操作的核心实现函数,展示了如何根据条件筛选集合中的元素。函数使用 @OptIn(ExperimentalJsExport::class) 和 @JsExport 注解,使其可以被编译成 JavaScript 并在 ArkTS 中调用。创建一个包含 1 到 10 的数字列表。使用 filter() 函数筛选偶数,条件为 it % 2 == 0,生成 [2, 4, 6, 8, 10]。使用 filter() 函数筛选大于 5 的数字,条件为 it > 5,生成 [6, 7, 8, 9, 10]。使用字符串模板和 joinToString() 格式化输出结果。这个函数展示了如何将过滤操作转换为用户友好的输出。
3. 聚合(Reduce/Fold)
将集合中的元素聚合为单个值。
@OptIn(ExperimentalJsExport::class)
@JsExport
fun aggregateExample(): String {
val numbers = listOf(1, 2, 3, 4, 5)
// 求和
val sum = numbers.sum()
// 求积
val product = numbers.fold(1) { acc, value -> acc * value }
// 最大值
val max = numbers.maxOrNull() ?: 0
// 最小值
val min = numbers.minOrNull() ?: 0
val result = "Numbers: ${numbers.joinToString(", ")}\n" +
"Sum: $sum\n" +
"Product: $product\n" +
"Max: $max\n" +
"Min: $min"
println(result)
return result
}
这是聚合操作的核心实现函数,展示了如何将集合中的元素聚合为单个值。函数使用 @OptIn(ExperimentalJsExport::class) 和 @JsExport 注解,使其可以被编译成 JavaScript 并在 ArkTS 中调用。创建一个包含 1 到 5 的数字列表。使用 sum() 函数计算总和,结果为 15。使用 fold() 函数计算乘积,初始值为 1,累加器 acc 和当前值 value 相乘,结果为 120。使用 maxOrNull() 函数获取最大值,如果列表为空则返回 null,使用 Elvis 操作符 ?: 提供默认值 0。使用 minOrNull() 函数获取最小值。使用字符串模板和 joinToString() 格式化输出结果。这个函数展示了如何将聚合操作转换为用户友好的输出。
4. 分组(GroupBy)
按条件将元素分组。
@OptIn(ExperimentalJsExport::class)
@JsExport
fun groupByExample(): String {
val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
// 按奇偶性分组
val grouped = numbers.groupBy { if (it % 2 == 0) "even" else "odd" }
val result = "Grouped by parity:\n" +
"Odd: ${grouped["odd"]?.joinToString(", ") ?: "none"}\n" +
"Even: ${grouped["even"]?.joinToString(", ") ?: "none"}"
println(result)
return result
}
这是分组操作的核心实现函数,展示了如何按条件将集合中的元素分组。函数使用 @OptIn(ExperimentalJsExport::class) 和 @JsExport 注解,使其可以被编译成 JavaScript 并在 ArkTS 中调用。创建一个包含 1 到 10 的数字列表。使用 groupBy() 函数按奇偶性分组,返回一个 Map,键为 “even” 或 “odd”,值为对应的元素列表。使用安全导航操作符 ?. 访问 Map 中的值,如果键不存在则返回 null。使用 Elvis 操作符 ?: 提供默认值 “none”。使用字符串模板和 joinToString() 格式化输出结果。这个函数展示了如何将分组操作转换为用户友好的输出。
5. 排序(Sort)
对集合进行排序。
@OptIn(ExperimentalJsExport::class)
@JsExport
fun sortExample(): String {
val numbers = listOf(5, 2, 8, 1, 9, 3)
val words = listOf("Zebra", "Apple", "Mango", "Banana")
// 升序排序
val sortedNumbers = numbers.sorted()
// 降序排序
val reverseSorted = numbers.sortedDescending()
// 按长度排序
val sortedByLength = words.sortedBy { it.length }
val result = "Original numbers: ${numbers.joinToString(", ")}\n" +
"Sorted: ${sortedNumbers.joinToString(", ")}\n" +
"Reverse sorted: ${reverseSorted.joinToString(", ")}\n" +
"Words by length: ${sortedByLength.joinToString(", ")}"
println(result)
return result
}
这是排序操作的核心实现函数,展示了如何对集合进行排序。函数使用 @OptIn(ExperimentalJsExport::class) 和 @JsExport 注解,使其可以被编译成 JavaScript 并在 ArkTS 中调用。创建一个无序的数字列表和一个单词列表。使用 sorted() 函数进行升序排序,结果为 [1, 2, 3, 5, 8, 9]。使用 sortedDescending() 函数进行降序排序,结果为 [9, 8, 5, 3, 2, 1]。使用 sortedBy() 函数按自定义条件排序,这里按单词长度排序。使用字符串模板和 joinToString() 格式化输出结果。这个函数展示了如何将排序操作转换为用户友好的输出。
实战案例
案例 1:数据统计
@OptIn(ExperimentalJsExport::class)
@JsExport
fun dataStatistics(): String {
data class Student(val name: String, val score: Int)
val students = listOf(
Student("Alice", 85),
Student("Bob", 92),
Student("Charlie", 78),
Student("David", 88),
Student("Eve", 95)
)
val averageScore = students.map { it.score }.average()
val topStudent = students.maxByOrNull { it.score }
val passCount = students.count { it.score >= 80 }
val result = "Total students: ${students.size}\n" +
"Average score: ${"%.2f".format(averageScore)}\n" +
"Top student: ${topStudent?.name} (${topStudent?.score})\n" +
"Pass count: $passCount"
println(result)
return result
}
这是数据统计的实战案例,展示了如何综合使用集合操作进行数据分析。函数使用 @OptIn(ExperimentalJsExport::class) 和 @JsExport 注解,使其可以被编译成 JavaScript 并在 ArkTS 中调用。定义一个 Student 数据类,包含学生名字和成绩。创建一个学生列表。使用 map() 提取所有学生的成绩,然后使用 average() 计算平均分。使用 maxByOrNull() 找到成绩最高的学生。使用 count() 统计及格(成绩 >= 80)的学生数量。使用字符串格式化 "%.2f".format() 保留两位小数。使用安全导航操作符 ?. 访问可能为 null 的对象属性。这个案例展示了如何将多个集合操作组合起来解决实际问题。
案例 2:字符串处理
@OptIn(ExperimentalJsExport::class)
@JsExport
fun stringProcessing(): String {
val text = "Hello World Kotlin Programming"
val words = text.split(" ")
val wordLengths = words.map { it.length }
val longestWord = words.maxByOrNull { it.length }
val uppercase = words.map { it.uppercase() }
val result = "Text: $text\n" +
"Words: ${words.joinToString(", ")}\n" +
"Word lengths: ${wordLengths.joinToString(", ")}\n" +
"Longest word: $longestWord\n" +
"Uppercase: ${uppercase.joinToString(", ")}"
println(result)
return result
}
这是字符串处理的实战案例,展示了如何使用集合操作处理文本数据。函数使用 @OptIn(ExperimentalJsExport::class) 和 @JsExport 注解,使其可以被编译成 JavaScript 并在 ArkTS 中调用。定义一个包含多个单词的文本字符串。使用 split(" ") 按空格分割文本为单词列表。使用 map() 提取每个单词的长度。使用 maxByOrNull() 找到最长的单词。使用 map() 将所有单词转换为大写。使用字符串模板和 joinToString() 格式化输出结果。这个案例展示了如何将集合操作应用于字符串处理任务。
性能考虑
1. 选择合适的集合类型
// 频繁查找 → 使用 Set
val set = setOf(1, 2, 3, 4, 5)
val contains = 3 in set // O(1)
// 频繁按索引访问 → 使用 List
val list = listOf(1, 2, 3, 4, 5)
val element = list[2] // O(1)
// 键值查找 → 使用 Map
val map = mapOf("a" to 1, "b" to 2)
val value = map["a"] // O(1)
这段代码展示了如何根据使用场景选择合适的集合类型。如果需要频繁查找元素,使用 Set 可以提供 O(1) 的查找时间复杂度。如果需要频繁按索引访问元素,使用 List 可以提供 O(1) 的访问时间复杂度。如果需要进行键值查找,使用 Map 可以提供 O(1) 的查找时间复杂度。选择合适的集合类型可以显著提高应用性能。
2. 避免不必要的复制
// ❌ 不好:创建多个中间集合
val result = numbers
.filter { it > 5 }
.map { it * 2 }
.filter { it < 20 }
.toList()
// ✅ 好:使用序列延迟计算
val result = numbers
.asSequence()
.filter { it > 5 }
.map { it * 2 }
.filter { it < 20 }
.toList()
这段代码对比了两种集合链式操作的性能差异。第一种方法直接在列表上链式调用 filter() 和 map(),每个操作都会创建一个中间列表,导致多次遍历和内存分配。第二种方法使用 asSequence() 将列表转换为序列,然后进行链式操作。Sequence 使用延迟计算,只在调用 toList() 时进行一次遍历,避免了创建多个中间集合。对于大数据集,使用 Sequence 可以显著提高性能。
3. 使用不可变集合
// 不可变集合更安全,编译器可以优化
val immutable = listOf(1, 2, 3) // 不可变
// 只在需要修改时使用可变集合
val mutable = mutableListOf(1, 2, 3)
mutable.add(4)
这段代码展示了如何优先使用不可变集合。使用 listOf() 创建不可变列表,不可变集合提供了更好的线程安全性和编译器优化机会。只在确实需要修改集合时才使用 mutableListOf() 创建可变列表。不可变集合可以被安全地共享和传递,减少了并发问题的风险。
常见问题
Q1: List 和 Array 有什么区别?
A:
- List:Kotlin 集合接口,更灵活,支持各种操作
- Array:固定大小,性能更好,更接近 Java 数组
val list = listOf(1, 2, 3) // List
val array = intArrayOf(1, 2, 3) // Array
Q2: 什么时候使用 Set?
A: 当你需要:
- 快速查找元素
- 自动去重
- 不关心顺序
val uniqueNumbers = setOf(1, 2, 2, 3, 3, 3) // {1, 2, 3}
Q3: 如何在 Map 中安全地获取值?
A: 使用 getOrNull() 或 getOrDefault()
val map = mapOf("a" to 1, "b" to 2)
// 安全获取
val value1 = map["c"] ?: 0 // 0
val value2 = map.getOrDefault("c", 0) // 0
Q4: 集合操作的链式调用会影响性能吗?
A: 会创建中间集合。使用 Sequence 可以避免:
// 创建 3 个中间列表
val result1 = list.filter { it > 5 }.map { it * 2 }.take(3)
// 使用 Sequence,延迟计算
val result2 = list.asSequence().filter { it > 5 }.map { it * 2 }.take(3).toList()
Q5: 如何处理空集合?
A: 使用 orEmpty() 或条件检查
val list: List<Int>? = null
// 安全处理
val size = list?.size ?: 0
val first = list?.firstOrNull()
val result = list.orEmpty().map { it * 2 }
总结
关键要点
- ✅ 选择合适的集合类型(List、Set、Map)
- ✅ 使用函数式操作(map、filter、fold 等)
- ✅ 优先使用不可变集合
- ✅ 考虑性能,使用 Sequence 处理大数据
- ✅ 安全处理空值和边界情况
更多推荐





所有评论(0)