本文由牛旦教育原创。
0.导言
本文主要是介绍在java中生成随机数的不同选择和方式。实际应用中根据自己的需要选择。
1.Java API
在Java本身自带的API中,为我们提供了几种方式来获得随机数。我们来看下。
1.1. java.lang.Math
Math类的random方法将返回一个范围为0.0(包括0.0)到1.0(不包括1.0)的双精度值。看看该如何使用它来获得一个在给定的范围(最小和最大值间)内定义的随机数:
int randomWithMathRandom = (int) ((Math.random() * (max - min)) min);
这行代码的意思为为,我们用两个整数,表示结果的随机数的取值范围在min和max之间。直接在JShell中简要演示这个实现,我这里参考如下(每次的结果可能都不同):
1.2. java.util.Random
在Java 1.7之前,最流行的生成随机数的方法是使用nextInt。有两种途径使用使用这个方法,即带参数和不带参数。无参数调用以近似相等的概率返回任何int值。所以很有可能得到负数,参考代码如下:
Random random = new Random();
int randomWithNextInt = random.nextInt();
我在本机JShell中运行结果如下:
如果使用绑定参数的netxInt方法(参数对返回值进行范围约定了),我们将得到一个范围内的数字,示例如下:
int aVal = random(ival) ;
注意:这类需要主要,ival值必须是大于0,返回值在0和ival之间,但不包含ival;若参数小于等于0,则会报错: java.lang.IllegalArgumentException.。
演示:那么要想得到一个在min和max之间的整数,我在JShell中演示结果如下:
Java 8引入了新的ints方法,此方法返回java.util.stream.IntStream。IntStream,LongStream,DoubleStream等用于操作流中的数据,同时提供了相应的静态方法来初始化它们自己。让我们看看如何使用它们。
没有参数的ints方法返回一个无限的int流,其代码示例如下:
IntStream unlimitedIntStream = random.ints();
也可以传入一个参数限制流大小,示例如下:
IntStream limitedIntStream = random.ints(streamSize);
当然,我们可以设置最大和最小值来生成带范围的int流,示例如下:
IntStream limitedIntStreamWithinARange = random.ints(streamSize, min, max);
具体用户可以查看Java API参考。
1.3. java.util.concurrent.ThreadLocalRandom
Java 1.7之后,为我们带来了一种通过ThreadLocalRandom类来生成随机数的更高效的新方法。这个类与随机类有三个重要区别:
- ü 不需要显式地初始化ThreadLocalRandom的新实例。这有助于避免创建大量无用实例和浪费垃圾收集器时间的错误;
- ü 不能为ThreadLocalRandom设置种子,这会导致一个实际的问题。如果我们需要设置种子,那么我们应该避免使用这种产生随机数的方式;
- ü Random (随机)类在多线程环境中表现不佳。
下面看看其工作方式:
int randomWithThreadLocalRandomInARange = ThreadLocalRandom.current().nextInt(min, max);
使用Java 8或更高版本,我们就有了新的可能性。
首先,nextInt方法有两种变体:
int randomWithThreadLocalRandom = ThreadLocalRandom.current().nextInt();
int randomWithThreadLocalRandomFromZero = ThreadLocalRandom.current().nextInt(max);
其次,更重要的是,我们可以使用ints方法:
IntStream streamWithThreadLocalRandom = ThreadLocalRandom.current().ints();
1.4. java.util.SplittableRandom
Java 8还给我们带来了一个非常快的生成器——SplittableRandom类。
正如我们在JavaDoc中看到的,这是一个用于并行计算的生成器。重要的是要知道实例不是线程安全的。所以,我们在使用这个类时必须小心。
还提供了nextInt和ints方法。使用nextInt,我们可以直接使用两个参数设置最高最低范围来调用:
SplittableRandom splittableRandom = new SplittableRandom();
int randomWithSplittableRandom = splittableRandom.nextInt(min, max);
这种方法可以检查max参数是否大于min,否则会得到一个IllegalArgumentException。但是,它不能检查我们是用正数还是负数。所以,参数都可以是任何负的。此外,我们还提供了一参和零参的调用。它们的工作方式和我们之前描述的一样。
也有ints方法。这意味着我们可以很容易地获得一个int流。必须清楚,使用中可以选择一个有限的或无限的流。对于一个有限的流,我们可以设置最高最低的数字生成范围约束:
IntStream limitedIntStreamWithinARangeWithSplittableRandom = splittableRandom.ints(streamSize, min, max);
1. .5. java.security.SecureRandom
如果我们有安全敏感的应用程序,或说安全要求高的,推荐考虑使用SecureRandom。这是一个加密的强生成器。默认构造的实例不使用加密随机种子。所以,我们应该:
- ü 设置种子-但种子将是不可预测的;
- ü 设置java.util.secureRandomSeed系统属性为true;
这个类继承自java.util.Random。因此,我们可以使用上面看到的所有方法。例如,如果我们需要获取任何int值,那么可调用没有参数的nextInt:
SecureRandom secureRandom = new SecureRandom();
int randomWithSecureRandom = secureRandom.nextInt();
另一方面,如果我们需要设置范围,我们可以调用带参数的方法:
int randomWithSecureRandomWithinARange = secureRandom.nextInt(max - min) min;
必须当心:如果参数不大于0,这种使用方法会抛出IllegalArgumentException。
2.第三方API
正如我们所看到的,Java为我们提供了许多生成随机数的类和方法。然而,还有第三方提供的API服务于此目的。我们来看看其中的一些。
2.1. org.apache.commons.math3.random.RandomDataGenerator
在Apache commons项目的commons数学库中有很多生成器。最简单,也可能最有用的就是RandomDataGenerator。它使用Well19937c(https://en.wikipedia.org/wiki/Well_equidistributed_long-period_linear)算法进行随机生成。但是,我们可以提供我们的算法实现。
让我们看看如何使用它。首先,我们必须添加依赖:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-math3</artifactId>
<version>3.6.1</version>
</dependency>
可以在Maven Central上找到commons-math3的最新版本。
导入项目后,就可以开始使用它们工作了,示例如下:
RandomDataGenerator randomDataGenerator = new RandomDataGenerator();
int randomWithRandomDataGenerator = randomDataGenerator.nextInt(min, max);
2.2. it.unimi.dsi.util.XoRoShiRo128PlusRandom
这是最快的随机数生成器实现之一。它是由米兰大学信息科学系开发的。
该库也可以在Maven中央存储库中使用。因此,让引用时可以如下添加依赖:
<dependency>
<groupId>it.unimi.dsi</groupId>
<artifactId>dsiutils</artifactId>
<version>2.6.0</version>
</dependency>
这个生成器继承自java.util.Random。但是,如果我们看一下JavaDoc,就会发现只有一种方法可以使用它——nextInt方法。最重要的是,此方法仅可用于零参数和单参数调用。其他任何调用都将直接使用java.util.Random随机方法。
例如,如想要得到一个范围内的随机数,你可以这样写:
XoRoShiRo128PlusRandom xoroRandom = new XoRoShiRo128PlusRandom();
int randomWithXoRoShiRo128PlusRandom = xoroRandom.nextInt(max - min) min;
3.最后
通过本文,我们知道了有几种实现随机数生成的方法。然而,没有最好的方法。因此,我们应该选择最适合我们需要的。
你还知道有哪些有趣的随机数生成类,分享一下吧.
,