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
。
可以生成 Double
、Int
、Long
类型的随机数,默认范围是:
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() |
非重复随机数序列 | 灵活但注意性能 |
根据实际需求选择合适的方法,才能写出高效、安全、易维护的代码 ✅