1. 概述

在处理数值时,我们经常会遇到需要判断一个数是正数还是负数的场景。

本文将探讨如何在 Kotlin 中高效地判断一个数字的正负性。我们将逐步构建一个符合 Kotlin 风格的通用函数,能够对任意 Number 类型的实例进行判断。

目标很明确:✅ 实现一个能识别 IntLongFloatDouble 等所有 Number 子类型,并返回其分类(正、负、零)的函数。

2. 问题引入

判断一个整数的正负很简单,但 Kotlin 的数值类型多样——IntLongFloatDouble 等都继承自抽象类 Number。如果我们为每种类型都写一个判断函数,那代码就太冗余了 ❌。

我们的目标是:编写一个统一的、idiomatic 的 Kotlin 函数,能处理所有 Number 类型

为了更清晰地表达结果,我们先定义一个枚举类:

enum class NumberCategory {
    Positive, Negative, Zero
}

接下来,我们从最简单的 Int 开始,逐步演进到通用方案。

3. 使用 if-else 表达式

最直接的方式就是与 0 比较。Kotlin 的 if-else 是表达式,可以直接返回值:

fun categoryOfInt1(n: Int): NumberCategory {
    return if (n > 0) {
        Positive
    } else if (n < 0) {
        Negative
    } else {
        Zero
    }
}

测试验证一下:

assertEquals(Positive, categoryOfInt1(42))
assertEquals(Negative, categoryOfInt1(-42))
assertEquals(Zero, categoryOfInt1(0))

测试通过 ✅。逻辑清晰,但略显啰嗦,可读性还有提升空间。

4. 使用 when 表达式优化

Kotlin 的 when 表达式在多分支判断时比 if-else 更简洁、更具可读性 ✅。

改写如下:

fun categoryOfInt2(n: Int): NumberCategory {
    return when {
        n > 0 -> Positive
        n < 0 -> Negative
        else -> Zero
    }
}

结构一目了然,测试同样通过:

assertEquals(Positive, categoryOfInt2(42))
assertEquals(Negative, categoryOfInt2(-42))
assertEquals(Zero, categoryOfInt2(0))

when 的无参形式在这里用得恰到好处,避免了冗余的条件判断。

5. 扩展至所有 Number 类型

上面的函数只支持 Int。如果要支持 LongFloat 等,难道要写一堆重载?显然不是 Kotlin 的风格 ❌。

核心思路

Number 类提供了 toDouble()toInt() 等转换方法。我们可以将任意 Number 转为 Double 进行比较。

⚠️ 为什么选 Double

  • Double 能表示的数值范围最大
  • 整型转 Double 不会丢失精度(在合理范围内)
  • 浮点型本身就是 Double 或可无损转为 Double

实现如下:

fun categoryOfNum(n: Number): NumberCategory {
    val d = n.toDouble()
    return when {
        d > 0.0 -> Positive
        d < 0.0 -> Negative
        else -> Zero
    }
}

全类型测试覆盖

// Int
assertEquals(Positive, categoryOfNum(42))
assertEquals(Negative, categoryOfNum(-42))
assertEquals(Zero, categoryOfNum(0))

// Long
assertEquals(Positive, categoryOfNum(42L))
assertEquals(Negative, categoryOfNum(-42L))
assertEquals(Zero, categoryOfNum(0L))

// Double
assertEquals(Positive, categoryOfNum(42.42))
assertEquals(Negative, categoryOfNum(-42.42))
assertEquals(Zero, categoryOfNum(0.00))

// Float
assertEquals(Positive, categoryOfNum(42.42f))
assertEquals(Negative, categoryOfNum(-42.42f))
assertEquals(Zero, categoryOfNum(0.00f))

全部通过 ✅。一个函数搞定所有数值类型,这才是我们要的通用解。

6. 进阶优化:使用扩展函数提升 API 友好性

虽然 categoryOfNum() 功能完整,但调用方式不够自然:categoryOfNum(42) 总感觉像在“外部加工”数据。

Kotlin 的扩展函数可以让我们把函数“挂”在 Number 上,调用更流畅:

fun Number.category(): NumberCategory {
    val d = toDouble()
    return when {
        d > 0.0 -> Positive
        d < 0.0 -> Negative
        else -> Zero
    }
}

现在调用变得非常自然:

// Int
assertEquals(Positive, 42.category())
assertEquals(Negative, (-42).category())
assertEquals(Zero, 0.category())

// Float
assertEquals(Positive, 42.42f.category())
assertEquals(Negative, (-42.42f).category())
assertEquals(Zero, 0.00f.category())

这种写法更符合 Kotlin 的惯用法(idiomatic),API 也更贴近开发者直觉 ✅。

7. 总结

我们从一个简单的 if-else 开始,逐步演化出一个通用、简洁、符合 Kotlin 风格的数值正负判断方案:

  1. 基础判断:用 when 替代 if-else,提升可读性
  2. 类型统一:利用 Number.toDouble() 实现多类型支持
  3. API 优化:通过扩展函数让调用更自然流畅

最终的 Number.category() 扩展函数既实用又优雅,可以直接集成到项目中。

示例完整代码已上传至 GitHub:https://github.com/Baeldung/kotlin-tutorials/tree/master/core-kotlin-modules/core-kotlin-numbers-2


原始标题:Check if a Number Is Positive or Negative in Kotlin