1. 理解问题
在 Kotlin 中,大于和小于的比较是编程中最基础的操作之一。通常,我们这样写:
val int1 = 1
val int2 = 2
val isInt1GreaterThanInt2 = int1 > int2
val isInt1LessThanInt2 = int1 < int2
这些操作符在底层调用的是 compareTo()
方法。该方法返回一个整数表示比较结果:
- 正数表示第一个值大于第二个
- 零表示两个值相等
- 负数表示第一个值小于第二个
⚠️ 但问题在于:如果比较的整数是可空类型(Int?
),直接使用这些操作符会导致编译错误。
因此,我们需要一种空安全的比较方式来处理可空整数。
2. 使用 compareTo()
方法
Kotlin 提供了一个简单的方法来比较可空整数,即使用 compareTo()
并结合安全调用操作符 ?.
:
fun compareTwoInts(a: Int?, b: Int?): Int? {
return a?.compareTo(b ?: return null)
}
这段代码做了以下几件事:
- 使用
a?.compareTo(...)
避免a
为 null 时调用方法 - 如果
b
为 null,则使用 Elvis 操作符(?:
)返回 null
✅ 这种方式简洁有效,适合直接比较两个可空整数。
我们来写个测试验证一下:
@Test
fun `compare nullable integers using compareTo`() {
val a: Int? = 5
val b: Int? = 3
val c: Int? = null
assertEquals(0, compareTwoInts(a, a))
assertEquals(1, compareTwoInts(a, b))
assertEquals(-1, compareTwoInts(b, a))
assertEquals(null, compareTwoInts(a, c))
assertEquals(null, compareTwoInts(c, b))
}
3. 创建扩展函数
为了复用比较逻辑,我们可以为 Int?
类型创建一个扩展函数:
fun Int?.isGreaterThan(other: Int?): Boolean? {
return this?.let {
it > (other ?: return null)
}
}
✅ 这样封装后,主逻辑更清晰,空值处理也统一了。
测试代码如下:
@Test
fun `compare nullable integers using extension function`() {
val a: Int? = 5
val b: Int? = 3
val c: Int? = null
assertEquals(true, a.isGreaterThan(b))
assertEquals(false, b.isGreaterThan(a))
assertEquals(null, c.isGreaterThan(a))
assertEquals(null, c.isGreaterThan(c))
}
3.1 创建通用比较函数
如果我们希望这个比较函数适用于所有实现了 Comparable
接口的类型(比如 String
),可以将其泛型化:
fun <T : Comparable<T>> T?.isGreaterThan(other: T?): Boolean? {
return this?.let { it > (other ?: return null) }
}
测试一下整数和字符串的比较:
@Test
fun `compare generic Int comparable types using extension function`() {
val a: Int? = 5
val b: Int? = 3
val c: Int? = null
assertEquals(true, a.isGreaterThan(b))
assertEquals(false, b.isGreaterThan(a))
assertEquals(false, b.isGreaterThan(b))
assertEquals(null, c.isGreaterThan(b))
}
@Test
fun `compare generic String comparable types using extension function`() {
val a: String? = "ABC"
val b: String? = "ZXY"
val c: String? = null
assertEquals(true, b.isGreaterThan(a))
assertEquals(false, a.isGreaterThan(b))
assertEquals(false, b.isGreaterThan(b))
assertEquals(null, c.isGreaterThan(b))
}
✅ 这种方式更通用,适用于任何实现了 Comparable
的类型。
4. 使用 Kotlin 的 compareValues()
函数
Kotlin 标准库中提供了一个专门用于比较两个可空值的函数 compareValues()
:
val result = compareValues(a, b)
⚠️ 与前面方法不同的是:compareValues()
会将 null
视为比任何非 null 值都小。
来看看它的行为:
@Test
fun `compare nullable integers using compareValues function`() {
val a: Int? = 5
val b: Int? = 3
val c: Int? = null
assertEquals(1, compareValues(a, b))
assertEquals(-1, compareValues(b, a))
assertEquals(1, compareValues(a, c))
assertEquals(-1, compareValues(c, a))
assertEquals(0, compareValues(c, c))
}
✅ 这个函数的优点是:
- 不需要手动处理 null
- 返回值始终是非 null 的整数
- 认为两个 null 是相等的(返回 0)
这在某些业务场景中非常有用,比如排序时希望 null 排在最前面或最后面。
5. 总结
方法 | 是否处理 null | 返回类型 | 是否通用 | 适用场景 |
---|---|---|---|---|
compareTo() |
✅ | Int? |
❌ | 简单比较两个可空整数 |
扩展函数 | ✅ | Boolean? |
✅(可泛型) | 封装比较逻辑,增强可读性 |
compareValues() |
✅ | Int |
✅ | 通用比较,适合排序等场景 |
📌 建议:
- 如果只是简单的比较,用
compareTo()
即可 - 如果希望代码更清晰,推荐使用扩展函数
- 如果要进行排序或统一处理 null 值,优先使用
compareValues()
选择哪种方式,取决于你的具体业务需求和代码风格。合理使用这些方法,可以避免空指针异常,提高代码的健壮性。