Java 中生成随机数的不同方法

发布于: 2020 年 07 月 19 日
Java中生成随机数的不同方法

使用Java API

java.lang.Math

Math类的random方法将返回一个[0.0, 1.0)范围内的double值。

//生成n以内随机整数[0, n)
int random = (int) (Math.random() * n)
//生成min到max范围的随机整数[min, max)
int randomWithRange = (int) (Math.random() * (max - min) + min);

java.util.Random

在Java 1.7之前,生成随机数最常用方法是使用nextInt。使用此方法有两种方法,带参数和不带参数。无参数调用以近似相同的概率返回任何int值。因此,我们很可能会得到负数:

Random random = new Random();
int randomInt = random.nextInt();

如果使用带参数的nextInt(int bound)方法,我们将获得范围内的数字:

//生成min到max范围的随机整数[min, max)
int randomWithRange = random.nextInt(max - min) + min;

nextInt(int bound)将为我们提供介于0(含)和参数(不含)之间的数字。因此,bound参数必须大于0。否则,我们将获得java.lang.IllegalArgumentException。

Java 8引入了新的ints方法,这些方法返回java.util.stream.IntStream。 让我们看看如何使用它们。

没有参数的ints方法将返回无限的int值流:

Random random = new Random();
IntStream intStream = random.ints();
//传入一个参数来限制流大小,返回包含2个随机数的流
IntStream intStreamLimit = random.ints(2);
//生成8个范围为[1, 10)的随机整数
IntStream limitedIntStreamWithinARange = random.ints(8, 1, 10);
//获取生成的8个随机数的最大值
System.out.println(limitedIntStreamWithinARange.max().getAsInt());

其他API参考:https://docs.oracle.com/javase/8/docs/api/java/util/Random.html

java.util.concurrent.ThreadLocalRandom

Java 1.7版本通过ThreadLocalRandom类为我们带来了一种新的,更有效的生成随机数的方法。这与Random类有三个重要区别:

  1. 我们不需要显式初始化ThreadLocalRandom的新实例。这有助于我们避免创建大量无用实例和浪费垃圾收集器时间的错误。

  2. 我们无法为ThreadLocalRandom设置种子,如果需要设置种子,则应避免这种生成随机数的方式

  3. Random类在多线程环境中表现不佳

int randomWithThreadLocalRandomInARange = ThreadLocalRandom.current().nextInt(min, max);
//java8之后的新特性,nextInt方法有两个变体
int randomWithThreadLocalRandom = ThreadLocalRandom.current().nextInt();
int randomWithThreadLocalRandomFromZero = ThreadLocalRandom.current().nextInt(max);
//还可以使用ints方法
IntStream streamWithThreadLocalRandom = ThreadLocalRandom.current().ints();

java.util.SplittableRandom

Java 8还提供了一个非常快速的生成器—SplittableRandom类。

这是一个用于并行计算的生成器。重要的是要知道实例不是线程安全的。因此,我们在使用这个类时必须小心。

我们有nextInt和ints方法可用。使用nextInt,我们可以使用两个参数调用直接设置顶部和底部范围:

SplittableRandom splittableRandom = new SplittableRandom();
int randomWithSplittableRandom = splittableRandom.nextInt(min, max);

这个方法需要检查参数max是否大于min,否则将抛出IllegalArgumentException异常。但是,它不检查我们是处理正数还是负数。任何参数都可以是负数。此外,我们还有可用的单参数和零参数调用。它们的工作方式和我们之前介绍的一样。

我们也可以使用ints方法。为了明确起见,我们可以选择有一个有限的或无限的流。对于一个有限的流,我们可以设置顶部和底部的数字生成范围:

IntStream limitedIntStreamWithinARangeWithSplittableRandom = splittableRandom.ints(streamSize, min, max);

java.security.SecureRandom

如果我们有对安全敏感的应用程序,则应考虑使用SecureRandom。这是一个加密强度很高的生成器。默认构造的实例不使用加密随机种子。因此,我们应该:

设置种子—因此,种子将是不可预测的

将java.util.secureRandomSeed系统属性设置为true

此类从java.util.Random继承。因此,我们可以使用上面看到的所有方法。例如,如果我们需要获取任何int值,则将不带参数调用nextInt:

SecureRandom secureRandom = new SecureRandom();
int randomWithSecureRandom = secureRandom.nextInt();
//如果需要设置范围,则可以使用bound参数进行调用
int randomWithSecureRandomWithinARange = secureRandom.nextInt(max - min) + min;

需要注意,参数需要大于零,否则将引发IllegalArgumentException。

使用第三方API

如前面介绍的那些,Java为我们提供了许多用于生成随机数的类和方法。但是,也有用于此目的的第三方API。

我们来看看其中的一些。

org.apache.commons.math3.random.RandomDataGenerator

在Apache commons项目的commons mathematics库中有很多生成器。最简单最有用的是RandomDataGenerator。采用Well19937c算法进行随机生成。但是,我们也可以提供我们的算法实现。

在pom.xml中添加依赖:

<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-math3</artifactId>
<version>3.6.1</version>
</dependency>

RandomDataGenerator randomDataGenerator = new RandomDataGenerator();
//生成范围为[min, max]的随机整数
int random = randomDataGenerator.nextInt(min, max);

it.unimi.dsi.util.XoRoShiRo128PlusRandom

这是最快的随机数生成器实现之一。它是由米兰大学信息科学系开发的。

在pom.xml中添加依赖:

<dependency>
<groupId>it.unimi.dsi</groupId>
<artifactId>dsiutils</artifactId>
<version>2.6.6</version>
</dependency>

该生成器继承自java.util.Random。但是,如果我们看一下JavaDoc,就会发现只有一种使用它的方法—通过nextInt方法。最重要的是,该方法仅适用于零参数和单参数调用。其他任何调用都将直接使用java.util.Random方法。

XoRoShiRo128PlusRandom xoroRandom = new XoRoShiRo128PlusRandom();
int randomWithXoRoShiRo128PlusRandom = xoroRandom.nextInt(max - min) + min;

用户头像

wjchenge

关注

还未添加个人签名 2018.07.27 加入

还未添加个人简介

评论

发布
暂无评论
Java中生成随机数的不同方法