You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin高效判断集合对象仅单个属性非空的实现方案

Kotlin中高效判断集合对象仅单个指定属性非null的方案

针对数据类属性较多时过滤条件冗余的问题,以下是几种通用且可维护的实现方式:

方案一:基于Kotlin反射的通用扩展函数(推荐)

利用Kotlin反射自动获取数据类的所有属性,无需手动维护属性列表,新增属性时完全不用修改过滤逻辑。为避免字符串拼写错误,使用属性引用而非字符串指定目标属性,兼顾类型安全。

实现步骤

首先在Gradle中添加kotlin-reflect依赖:

implementation("org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion")

然后定义通用扩展函数:

import kotlin.reflect.KProperty1
import kotlin.reflect.full.declaredMemberProperties

/**
 * 判断对象是否仅指定属性非null,其余所有属性均为null
 * @param property 目标属性的引用(如Person::age)
 */
fun <T> T.hasOnlyNonNullProperty(property: KProperty1<T, *>): Boolean {
    val allProperties = this::class.declaredMemberProperties
    // 先检查目标属性是否非null
    val targetValue = property.get(this) ?: return false
    // 检查其余所有属性是否均为null
    return allProperties.filter { it != property }.all { it.get(this) == null }
}

使用示例

data class Person(val name: String?, val age: Int?, val address: String?, val phone: String?)

val people = listOf(
    Person("Mary", 20, "Street 111", null),
    Person(null, 22, null, null), // 仅age非null
    Person(null, 21, "Street 123", null),
    Person(null, null, null, "123456") // 仅phone非null
)

// 过滤仅age非null的元素
val filteredAgeOnly = people.filter { it.hasOnlyNonNullProperty(Person::age) }
// 过滤仅phone非null的元素
val filteredPhoneOnly = people.filter { it.hasOnlyNonNullProperty(Person::phone) }

println(filteredAgeOnly) // 输出 [Person(name=null, age=22, address=null, phone=null)]
println(filteredPhoneOnly) // 输出 [Person(name=null, age=null, address=null, phone=123456)]

优缺点

  • ✅ 新增属性无需修改过滤逻辑,可维护性极强
  • ✅ 类型安全,避免字符串拼写错误
  • ❌ 反射存在轻微性能开销,适合绝大多数非性能敏感场景

方案二:手动维护属性列表(性能优先)

如果对性能要求极高(如百万级数据循环处理),可以手动维护数据类的属性值列表,避免反射开销。

实现代码

data class Person(val name: String?, val age: Int?, val address: String?, val phone: String?) {
    // 手动返回所有属性值的列表,新增属性时需同步更新此方法
    fun getAllPropertyValues(): List<Any?> = listOf(name, age, address, phone)
}

// 过滤仅age非null的元素
val filteredAgeOnly = people.filter {
    it.age != null && it.getAllPropertyValues().count { value -> value != null } == 1
}

优缺点

  • ✅ 无反射开销,性能最优
  • ❌ 新增属性时必须手动更新getAllPropertyValues方法,存在维护成本

方案三:代码生成(兼顾通用与性能)

对于大型项目,可使用KSP(Kotlin Symbol Processing)生成每个数据类的属性检查代码,既保留反射的通用性,又避免运行时反射开销。不过需要额外配置代码生成插件,适合属性频繁变更且对性能有要求的场景。

内容的提问来源于stack exchange,提问作者Muchtar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 13:03:31