1. 简介

本文将介绍在 Kotlin 中生成随机数的几种常见方式。适用于不同场景下的需求,包括生成单个随机数、指定范围内的随机数,以及非重复随机数序列的生成。

2. 使用 java.lang.Math

这是最简单的方式,调用 Math.random() 方法会返回一个介于 0(包含)和 1(不包含)之间的 Double 值。

@Test
fun whenRandomNumberWithJavaUtilMath_thenResultIsBetween0And1() {
    val randomNumber = Math.random()
    assertTrue { randomNumber >= 0.0 }
    assertTrue { randomNumber < 1.0 }
}

✅ 优点:简单直接
❌ 缺点:只能生成 Double 类型,且范围固定

3. 使用 ThreadLocalRandom

ThreadLocalRandom 是 Java 提供的线程安全随机数生成器,适用于多线程环境,性能优于普通 Random

可以生成 DoubleIntLong 类型的随机数,默认范围是:

  • Double:[0.0, 1.0)
  • Int:[-2^31, 2^31)
  • Long:[-2^63, 2^63)

示例:

@Test
fun whenRandomNumberWithJavaThreadLocalRandom_thenResultsInDefaultRanges() {
    val randomDouble = ThreadLocalRandom.current().nextDouble()
    val randomInteger = ThreadLocalRandom.current().nextInt()
    val randomLong = ThreadLocalRandom.current().nextLong()
    assertTrue { randomDouble >= 0.0 && randomDouble < 1.0 }
    assertTrue { randomInteger >= Int.MIN_VALUE && randomInteger < Int.MAX_VALUE }
    assertTrue { randomLong >= Long.MIN_VALUE && randomLong < Long.MAX_VALUE }
}

✅ 优点:线程安全、性能好、支持多种类型
⚠️ 注意:使用时要调用 current() 获取当前线程的实例

4. 使用 Kotlin/JS 的 Math

在 Kotlin/JS 环境中,也可以使用 kotlin.math 包中的 Math.random() 方法生成 0 到 1 之间的随机数。

@Test
fun whenRandomNumberWithKotlinJSMath_thenResultIsBetween0And1() {
    val randomDouble = Math.random()
    assertTrue { randomDouble >= 0.0 }
    assertTrue { randomDouble < 1.0 }
}

⚠️ 仅适用于 Kotlin/JS 项目,JVM 环境不适用

5. 使用纯 Kotlin 生成指定范围的随机数

可以通过创建一个数字范围,然后调用 shuffled() 打乱顺序,再取第一个元素来实现:

@Test
fun whenRandomNumberWithKotlinNumberRange_thenResultInGivenRange() {
    val randomInteger = (1..12).shuffled().first()
    assertTrue { randomInteger in 1..12 }
}

✅ 优点:Kotlin 原生支持,代码简洁
❌ 缺点:性能略逊于 ThreadLocalRandom,尤其在频繁调用时

6. 使用 ThreadLocalRandom 生成指定范围的随机数

ThreadLocalRandom 也支持生成指定范围的随机数:

@Test
fun whenRandomNumberWithJavaThreadLocalRandom_thenResultsInGivenRanges() {
    val randomDouble = ThreadLocalRandom.current().nextDouble(1.0, 10.0)
    val randomInteger = ThreadLocalRandom.current().nextInt(1, 10)
    val randomLong = ThreadLocalRandom.current().nextLong(1, 10)
    assertTrue { randomDouble >= 1.0 && randomDouble < 10.0 }
    assertTrue { randomInteger >= 1 && randomInteger < 10 }
    assertTrue { randomLong >= 1L && randomLong < 10L }
}

✅ 优点:支持范围指定、线程安全、性能好
⚠️ 注意:右边界是开区间,即不包含上限

7. 伪随机数与安全随机数

Java 的 Random 类默认使用 线性同余生成器(Linear Congruential Generator),是一种伪随机数生成算法。

✅ 优点:速度快
❌ 缺点:安全性差,容易被预测

在涉及安全的场景(如生成令牌、密码等)应使用 SecureRandom

@Test
fun whenRandomNumberWithJavaSecureRandom_thenResultsInGivenRanges() {
    val secureRandom = SecureRandom()
    val randomInt = secureRandom.nextInt(100)
    assertTrue { randomInt >= 0 && randomInt < 100 }
}

SecureRandom 使用的是 加密安全伪随机数生成器(CSPRNG),具有更高的安全性。

⚠️ 踩坑提醒:在安全场景下,千万不要使用普通随机数生成器

8. 在 Kotlin 中生成非重复随机数

有些场景下我们需要生成一个不重复的随机数序列,Kotlin 提供了两种常见方式:

8.1 使用 shuffled()

通过打乱一个固定范围的列表,再从中取值,可以确保不重复:

@Test
fun whenRandomNonRepeatingNumbersWithShuffle_thenResultsAreUnique() {
    val randomNumbers = (1..10).shuffled().take(5)
    assertTrue { randomNumbers.distinct().size == randomNumbers.size }
}

✅ 优点:简单直观
❌ 缺点:范围有限,适合小数据量

8.2 使用 generateSequence + distinct()

使用 Kotlin 的序列生成方式,结合去重函数,可以按需生成非重复的随机数:

@Test
fun whenRandomNonRepeatingNumbersWithSequence_thenResultsAreUnique() {
    val randomNumbers = generateSequence { Random.nextInt(1, 11) }.distinct().take(5).toList()
    assertTrue { randomNumbers.distinct().size == randomNumbers.size }
}

✅ 优点:可无限生成,灵活
⚠️ 性能提示:随着已生成数增多,去重效率会下降

9. 总结

本文总结了在 Kotlin 中生成随机数的多种方式,适用于不同场景:

方法 适用场景 说明
Math.random() 快速生成 0-1 之间 Double 简单但功能有限
ThreadLocalRandom 多线程、指定范围 性能好,推荐使用
Kotlin/JS Math Kotlin/JS 项目 不适用于 JVM
shuffled() 小范围随机取值 简洁但效率一般
SecureRandom 安全相关场景 必须使用
generateSequence + distinct() 非重复随机数序列 灵活但注意性能

根据实际需求选择合适的方法,才能写出高效、安全、易维护的代码 ✅


原始标题:Get a Random Number in Kotlin