KMP 实现鸿蒙跨端:Kotlin 过滤操作和条件筛选指南
本文介绍了Kotlin Multiplatform(KMP)在鸿蒙跨端开发中的过滤操作和条件筛选。主要内容包括:基础过滤(filter、filterNot、filterIsInstance等)、高级过滤技巧(链式过滤、条件转换)、条件检查方法(any/all/none)、分组分割操作(groupBy/partition),以及性能优化建议。通过KMP技术,这些过滤操作可以编译为JavaScript
目录
概述
本文档介绍如何在 Kotlin Multiplatform (KMP) 鸿蒙跨端开发中进行过滤操作和条件筛选。过滤是数据处理中最常见的操作之一。Kotlin 提供了强大而灵活的过滤 API,允许我们根据各种条件从集合中筛选出需要的元素。通过 KMP,这些过滤操作可以无缝编译到 JavaScript,在 OpenHarmony 应用中高效运行。
为什么需要学习过滤操作?
-
数据清洗:从原始数据中提取有效数据,支持鸿蒙应用的数据处理
-
业务逻辑:根据条件筛选符合要求的数据,实现复杂的业务需求
-
性能优化:及早过滤可以减少后续处理的数据量,提高应用性能
-
代码简洁:使用函数式过滤比循环更清晰,提高代码可维护性
-
链式操作:可以组合多个过滤条件,实现复杂的数据处理流程
-
跨端兼容:过滤操作在编译到 JavaScript 时表现出色,完美支持 OpenHarmony 应用
基础过滤
filter - 基础过滤
filter 函数根据条件筛选元素,返回满足条件的元素列表。
// 基础用法
val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
// 筛选偶数
val evens = numbers.filter { it % 2 == 0 }
println(evens) // [2, 4, 6, 8, 10]
// 筛选大于 5 的数字
val greaterThan5 = numbers.filter { it > 5 }
println(greaterThan5) // [6, 7, 8, 9, 10]
// 筛选小于 3 的数字
val lessThan3 = numbers.filter { it < 3 }
println(lessThan3) // [1, 2]
filterNot - 反向过滤
filterNot 返回不满足条件的元素。
val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
// 筛选非偶数(奇数)
val odds = numbers.filterNot { it % 2 == 0 }
println(odds) // [1, 3, 5, 7, 9]
// 筛选不大于 5 的数字
val notGreaterThan5 = numbers.filterNot { it > 5 }
println(notGreaterThan5) // [1, 2, 3, 4, 5]
filterIsInstance - 类型过滤
按类型过滤集合中的元素。
val mixed = listOf(1, "hello", 2.5, "world", 3, true) // 筛选整数 val integers = mixed.filterIsInstance<Int>() println(integers) // [1, 3] // 筛选字符串 val strings = mixed.filterIsInstance<String>() println(strings) // [hello, world] // 筛选浮点数 val doubles = mixed.filterIsInstance<Double>() println(doubles) // [2.5]
filterIndexed - 带索引的过滤
根据元素索引进行过滤。
val numbers = listOf(10, 20, 30, 40, 50)
// 筛选索引为偶数的元素
val evenIndices = numbers.filterIndexed { index, _ -> index % 2 == 0 }
println(evenIndices) // [10, 30, 50]
// 筛选索引大于 1 且值大于 20 的元素
val filtered = numbers.filterIndexed { index, value -> index > 1 && value > 20 }
println(filtered) // [30, 40, 50]
高级过滤
链式过滤
将多个过滤条件组合使用。
Kotlin 源代码
@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 }
// 链式过滤:大于 3 且小于 8
val result = numbers
.filter { it > 3 }
.filter { it < 8 }
return "原始数据: ${numbers.joinToString(", ")}\n" +
"偶数: ${evens.joinToString(", ")}\n" +
"大于5: ${greaterThan5.joinToString(", ")}\n" +
"3到8之间: ${result.joinToString(", ")}"
}
编译后的 JavaScript 代码
function filterExample() {
var numbers = listOf([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
// 筛选偶数
var destination = ArrayList_init_$Create$();
var _iterator__ex2g4s = numbers.b();
while (_iterator__ex2g4s.c()) {
var element = _iterator__ex2g4s.d();
if ((element % 2 | 0) === 0) {
destination.t(element);
}
}
var evens = destination;
// 筛选大于 5 的数字
var destination_0 = ArrayList_init_$Create$();
var _iterator__ex2g4s_0 = numbers.b();
while (_iterator__ex2g4s_0.c()) {
var element_0 = _iterator__ex2g4s_0.d();
if (element_0 > 5) {
destination_0.t(element_0);
}
}
var greaterThan5 = destination_0;
// 链式过滤:大于 3 且小于 8
var destination_1 = ArrayList_init_$Create$();
var _iterator__ex2g4s_1 = numbers.b();
while (_iterator__ex2g4s_1.c()) {
var element_1 = _iterator__ex2g4s_1.d();
if (element_1 > 3) {
destination_1.t(element_1);
}
}
var temp = destination_1;
var destination_2 = ArrayList_init_$Create$();
var _iterator__ex2g4s_2 = temp.b();
while (_iterator__ex2g4s_2.c()) {
var element_2 = _iterator__ex2g4s_2.d();
if (element_2 < 8) {
destination_2.t(element_2);
}
}
var result = destination_2;
var result_str = "原始数据: " + joinToString(numbers, ", ") + "\n" +
"偶数: " + joinToString(evens, ", ") + "\n" +
"大于5: " + joinToString(greaterThan5, ", ") + "\n" +
"3到8之间: " + joinToString(result, ", ");
println(result_str);
return result_str;
}
ArkTS 调用代码
import { filterExample } from './hellokjs';
@Entry
@Component
struct Index {
@State message: string = '加载中...';
@State results: string[] = [];
aboutToAppear(): void {
this.loadResults();
}
loadResults(): void {
try {
// 调用 Kotlin 编译的 JavaScript 函数
const filter = filterExample();
this.results = [filter];
this.message = '案例已加载';
} catch (error) {
this.message = `错误: ${error}`;
}
}
build() {
Column() {
Text('Kotlin 过滤操作案例演示')
.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')
}
}
执行流程说明
-
Kotlin 源代码:定义
filterExample()函数,使用 Kotlin 的filter操作符 -
编译过程:Gradle 使用 KMP 编译器将 Kotlin 代码编译成 JavaScript
-
JavaScript 输出:编译器生成优化的 JavaScript 代码,使用循环和条件判断实现过滤逻辑
-
ArkTS 调用:在 OpenHarmony 应用中导入并调用编译后的 JavaScript 函数
-
结果展示:在 UI 中显示过滤结果
过滤后转换
结合 filter 和 map 进行数据转换。在实际项目中,可以参考上面的 filterExample() 案例进行扩展。
使用自定义条件
定义复杂的过滤条件。在实际项目中,可以根据业务需求自定义过滤条件,参考上面的 filterExample() 案例的实现方式。
条件检查
any - 是否存在满足条件的元素
val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
// 是否存在偶数
val hasEven = numbers.any { it % 2 == 0 }
println(hasEven) // true
// 是否存在大于 100 的数字
val hasLarge = numbers.any { it > 100 }
println(hasLarge) // false
// 空集合
val empty = emptyList<Int>()
println(empty.any { it > 0 }) // false
all - 是否所有元素都满足条件
val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
// 是否所有元素都是正数
val allPositive = numbers.all { it > 0 }
println(allPositive) // true
// 是否所有元素都是偶数
val allEven = numbers.all { it % 2 == 0 }
println(allEven) // false
// 是否所有元素都小于 20
val allSmall = numbers.all { it < 20 }
println(allSmall) // true
none - 是否没有元素满足条件
val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
// 是否没有负数
val noNegative = numbers.none { it < 0 }
println(noNegative) // true
// 是否没有偶数
val noEven = numbers.none { it % 2 == 0 }
println(noEven) // false
// 是否没有大于 100 的数字
val noLarge = numbers.none { it > 100 }
println(noLarge) // true
条件检查示例
@OptIn(ExperimentalJsExport::class)
@JsExport
fun conditionCheckExample(): String {
val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
val hasEven = numbers.any { it % 2 == 0 }
val allPositive = numbers.all { it > 0 }
val noNegative = numbers.none { it < 0 }
return "数字: ${numbers.joinToString(", ")}\n" +
"存在偶数: $hasEven\n" +
"全部为正数: $allPositive\n" +
"没有负数: $noNegative"
}
分组和分割
groupBy - 按条件分组
val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
// 按奇偶性分组
val grouped = numbers.groupBy { if (it % 2 == 0) "偶数" else "奇数" }
println(grouped)
// {偶数=[2, 4, 6, 8, 10], 奇数=[1, 3, 5, 7, 9]}
// 按模 3 分组
val groupedBy3 = numbers.groupBy { it % 3 }
println(groupedBy3)
// {1=[1, 4, 7, 10], 2=[2, 5, 8], 0=[3, 6, 9]}
partition - 分割成两部分
val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
// 分割成偶数和奇数
val (evens, odds) = numbers.partition { it % 2 == 0 }
println("偶数: $evens") // [2, 4, 6, 8, 10]
println("奇数: $odds") // [1, 3, 5, 7, 9]
// 分割成大于 5 和小于等于 5
val (large, small) = numbers.partition { it > 5 }
println("大于5: $large") // [6, 7, 8, 9, 10]
println("≤5: $small") // [1, 2, 3, 4, 5]
分组示例
@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) "偶数" else "奇数" }
val result = mutableListOf<String>()
grouped.forEach { (key, values) ->
result.add("$key: ${values.joinToString(", ")}")
}
return "按奇偶分组:\n${result.joinToString("\n")}"
}
实战案例
案例:过滤操作的实际应用
在上面的"高级过滤"部分已经展示了完整的三层代码示例(Kotlin、JavaScript、ArkTS)。这个 filterExample() 案例演示了:

-
基础过滤:筛选偶数和大于 5 的数字
-
链式过滤:组合多个过滤条件(大于 3 且小于 8)
-
编译过程:展示了 Kotlin 代码如何编译成 JavaScript
-
实际调用:展示了如何在 ArkTS 中调用编译后的函数
扩展应用场景
在实际项目中,可以基于 filterExample() 的模式进行扩展:
-
数据清洗:过滤无效数据(如年龄 >= 18 的用户)
-
商品筛选:按类别、价格范围、评分等条件筛选产品
-
订单统计:筛选特定状态的订单并进行统计
-
日志分析:过滤特定级别或时间范围的日志
所有这些应用都遵循相同的 Kotlin → JavaScript → ArkTS 的编译和调用流程。
性能优化
1. 及早过滤
// ✅ 好:先过滤再转换
val result = numbers
.filter { it > 5 }
.map { it * 2 }
// ❌ 不好:先转换再过滤
val result = numbers
.map { it * 2 }
.filter { it > 10 }
2. 使用 Sequence 处理大数据
// ✅ 好:使用 Sequence 延迟计算
val result = numbers
.asSequence()
.filter { it > 5 }
.map { it * 2 }
.toList()
// ❌ 不好:创建多个中间列表
val result = numbers
.filter { it > 5 }
.map { it * 2 }
3. 避免重复过滤
// ✅ 好:合并条件
val result = numbers.filter { it > 5 && it < 20 }
// ❌ 不好:重复过滤
val result = numbers
.filter { it > 5 }
.filter { it < 20 }
4. 选择合适的操作
// ✅ 好:使用专门的函数
val hasEven = numbers.any { it % 2 == 0 }
// ❌ 不好:使用 filter 再检查
val hasEven = numbers.filter { it % 2 == 0 }.isNotEmpty()
常见问题
Q1: filter 和 filterNot 有什么区别?
A:
-
filter:返回满足条件的元素 -
filterNot:返回不满足条件的元素
val numbers = listOf(1, 2, 3, 4, 5)
val evens = numbers.filter { it % 2 == 0 } // [2, 4]
val odds = numbers.filterNot { it % 2 == 0 } // [1, 3, 5]
Q2: 什么时候使用 any/all/none?
A:
-
any:检查是否存在满足条件的元素 -
all:检查是否所有元素都满足条件 -
none:检查是否没有元素满足条件
val numbers = listOf(1, 2, 3, 4, 5)
numbers.any { it > 3 } // true(存在 4, 5)
numbers.all { it > 0 } // true(全部为正数)
numbers.none { it < 0 } // true(没有负数)
Q3: filter 和 partition 有什么区别?
A:
-
filter:返回满足条件的元素 -
partition:返回满足和不满足条件的两个列表
val numbers = listOf(1, 2, 3, 4, 5)
val evens = numbers.filter { it % 2 == 0 } // [2, 4]
val (evens2, odds) = numbers.partition { it % 2 == 0 } // [2, 4], [1, 3, 5]
Q4: 如何处理空集合的过滤?
A: 使用安全操作符和默认值
val list: List<Int>? = null
// 安全处理
val filtered = list?.filter { it > 5 } ?: emptyList()
// 或使用 orEmpty()
val filtered = list.orEmpty().filter { it > 5 }
Q5: 过滤大数据集时如何提高性能?
A: 使用 Sequence 避免创建中间集合
// ✅ 好:使用 Sequence
val result = largeList
.asSequence()
.filter { it > 5 }
.map { it * 2 }
.filter { it < 100 }
.toList()
// ❌ 不好:创建多个中间列表
val result = largeList
.filter { it > 5 }
.map { it * 2 }
.filter { it < 100 }
总结
关键要点
-
✅
filter是最常用的过滤操作 -
✅
any/all/none用于条件检查 -
✅ 链式过滤可以组合多个条件
-
✅
partition可以同时获得两部分数据 -
✅ 使用 Sequence 优化大数据处理性能
下一步
-
学习更多高级过滤技巧
-
实践复杂的数据筛选场景
-
优化过滤操作的性能
-
探索自定义过滤扩展函数
参考资源
更多推荐



所有评论(0)