在这里插入图片描述

目录

  1. 概述
  2. 集合类型
  3. 基础操作
  4. 高级操作
  5. 实战案例
  6. 性能考虑
  7. 常见问题

概述

本文档介绍如何使用 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(),获取列表操作结果,然后更新 resultsmessage。使用 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(),获取映射操作结果,然后更新 resultsmessage。使用 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 处理大数据
  • ✅ 安全处理空值和边界情况
Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐