Java 中生成随机数的不同方法
使用Java API
java.lang.Math
Math类的random方法将返回一个[0.0, 1.0)范围内的double值。
java.util.Random
在Java 1.7之前,生成随机数最常用方法是使用nextInt。使用此方法有两种方法,带参数和不带参数。无参数调用以近似相同的概率返回任何int值。因此,我们很可能会得到负数:
如果使用带参数的nextInt(int bound)方法,我们将获得范围内的数字:
nextInt(int bound)将为我们提供介于0(含)和参数(不含)之间的数字。因此,bound参数必须大于0。否则,我们将获得java.lang.IllegalArgumentException。
Java 8引入了新的ints方法,这些方法返回java.util.stream.IntStream。 让我们看看如何使用它们。
没有参数的ints方法将返回无限的int值流:
其他API参考:https://docs.oracle.com/javase/8/docs/api/java/util/Random.html
java.util.concurrent.ThreadLocalRandom
Java 1.7版本通过ThreadLocalRandom类为我们带来了一种新的,更有效的生成随机数的方法。这与Random类有三个重要区别:
我们不需要显式初始化ThreadLocalRandom的新实例。这有助于我们避免创建大量无用实例和浪费垃圾收集器时间的错误。
我们无法为ThreadLocalRandom设置种子,如果需要设置种子,则应避免这种生成随机数的方式
Random类在多线程环境中表现不佳
java.util.SplittableRandom
Java 8还提供了一个非常快速的生成器—SplittableRandom类。
这是一个用于并行计算的生成器。重要的是要知道实例不是线程安全的。因此,我们在使用这个类时必须小心。
我们有nextInt和ints方法可用。使用nextInt,我们可以使用两个参数调用直接设置顶部和底部范围:
这个方法需要检查参数max是否大于min,否则将抛出IllegalArgumentException异常。但是,它不检查我们是处理正数还是负数。任何参数都可以是负数。此外,我们还有可用的单参数和零参数调用。它们的工作方式和我们之前介绍的一样。
我们也可以使用ints方法。为了明确起见,我们可以选择有一个有限的或无限的流。对于一个有限的流,我们可以设置顶部和底部的数字生成范围:
java.security.SecureRandom
如果我们有对安全敏感的应用程序,则应考虑使用SecureRandom。这是一个加密强度很高的生成器。默认构造的实例不使用加密随机种子。因此,我们应该:
设置种子—因此,种子将是不可预测的
将java.util.secureRandomSeed系统属性设置为true
此类从java.util.Random继承。因此,我们可以使用上面看到的所有方法。例如,如果我们需要获取任何int值,则将不带参数调用nextInt:
需要注意,参数需要大于零,否则将引发IllegalArgumentException。
使用第三方API
如前面介绍的那些,Java为我们提供了许多用于生成随机数的类和方法。但是,也有用于此目的的第三方API。
我们来看看其中的一些。
org.apache.commons.math3.random.RandomDataGenerator
在Apache commons项目的commons mathematics库中有很多生成器。最简单最有用的是RandomDataGenerator。采用Well19937c算法进行随机生成。但是,我们也可以提供我们的算法实现。
在pom.xml中添加依赖:
it.unimi.dsi.util.XoRoShiRo128PlusRandom
这是最快的随机数生成器实现之一。它是由米兰大学信息科学系开发的。
在pom.xml中添加依赖:
该生成器继承自java.util.Random。但是,如果我们看一下JavaDoc,就会发现只有一种使用它的方法—通过nextInt方法。最重要的是,该方法仅适用于零参数和单参数调用。其他任何调用都将直接使用java.util.Random方法。
评论