Generating Random Numbers in Java – 在Java中生成随机数

最后修改: 2020年 1月 14日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this tutorial, we’ll explore different ways of generating random numbers in Java.

在本教程中,我们将探讨在Java中生成随机数的不同方法。

2. Using Java API

2.使用Java API

The Java API provides us with several ways to achieve our purpose. Let’s see some of them.

Java API为我们提供了几种方法来实现我们的目的。让我们看看其中的一些。

2.1. java.lang.Math

2.1.java.lang.Math

The random method of the Math class will return a double value in a range from 0.0 (inclusive) to 1.0 (exclusive). Let’s see how we’d use it to get a random number in a given range defined by min and max:

Math类的random方法将返回一个double值,范围从0.0(包括)到1.0(不包括)。让我们看看如何使用它来获得一个由minmax定义的特定范围的随机数。

int randomWithMathRandom = (int) ((Math.random() * (max - min)) + min);

2.2. java.util.Random

2.2.java.util.Random

Before Java 1.7, the most popular way of generating random numbers was using nextInt. There were two ways of using this method, with and without parameters. The no-parameter invocation returns any of the int values with approximately equal probability. So, it’s very likely that we’ll get negative numbers:

在Java 1.7之前,最流行的生成随机数的方法是使用nextInt有两种使用该方法的方式,即有参数和无参数。无参数的调用以近似相等的概率返回任何一个int值。所以,我们很有可能会得到负数。

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

If we use the netxInt invocation with the bound parameter, we’ll get numbers within a range:

如果我们使用带有bound参数的netxInt调用,我们将得到一个范围内的数字。

int randomWintNextIntWithinARange = random.nextInt(max - min) + min;

This will give us a number between 0 (inclusive) and parameter (exclusive). So, the bound parameter must be greater than 0. Otherwise, we’ll get a java.lang.IllegalArgumentException.

这将给我们一个介于0(包容)和参数(排斥)之间的数字。所以,绑定的参数必须大于0。否则,我们会得到一个java.lang.IllegalArgumentException

Java 8 introduced the new ints methods that return a java.util.stream.IntStream. Let’s see how to use them.

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

The ints method without parameters returns an unlimited stream of int values:

不带参数的ints方法返回一个无限的int值流。

IntStream unlimitedIntStream = random.ints();

We can also pass in a single parameter to limit the stream size:

我们也可以传入一个参数来限制流的大小。

IntStream limitedIntStream = random.ints(streamSize);

And, of course, we can set the maximum and minimum for the generated range:

当然,我们还可以为生成的范围设置最大和最小。

IntStream limitedIntStreamWithinARange = random.ints(streamSize, min, max);

2.3. java.util.concurrent.ThreadLocalRandom

2.3.java.util.concurrent.ThreadLocalRandom

Java 1.7 release brought us a new and more efficient way of generating random numbers via the ThreadLocalRandom class. This one has three important differences from the Random class:

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

  • We don’t need to explicitly initiate a new instance of ThreadLocalRandom. This helps us to avoid mistakes of creating lots of useless instances and wasting garbage collector time
  • We can’t set the seed for ThreadLocalRandom, which can lead to a real problem. If we need to set the seed, then we should avoid this way of generating random numbers
  • Random class doesn’t perform well in multi-threaded environments

Now, let’s see how it works:

现在,让我们看看它是如何工作的。

int randomWithThreadLocalRandomInARange = ThreadLocalRandom.current().nextInt(min, max);

With Java 8 or above, we have new possibilities. Firstly, we have two variations for the nextInt method:

在Java 8或以上版本中,我们有了新的可能性。首先,我们有两个nextInt方法的变化。

int randomWithThreadLocalRandom = ThreadLocalRandom.current().nextInt();
int randomWithThreadLocalRandomFromZero = ThreadLocalRandom.current().nextInt(max);

Secondly, and more importantly, we can use the ints method:

其次,更重要的是,我们可以使用ints方法。

IntStream streamWithThreadLocalRandom = ThreadLocalRandom.current().ints();

2.4. java.util.SplittableRandom

2.4. java.util.SplittableRandom[/em]

Java 8 has also brought us a really fast generator — the SplittableRandom class.

Java 8还为我们带来了一个真正快速的生成器–SplittableRandom类。

As we can see in the JavaDoc, this is a generator for use in parallel computations. It’s important to know that the instances are not thread-safe. So, we have to take care when using this class.

正如我们在JavaDoc中看到的,这是一个用于并行计算的生成器。重要的是要知道,这些实例不是线程安全的。所以,我们在使用这个类的时候必须要小心。

We have available the nextInt and ints methods. With nextInt we can set directly the top and bottom range using the two parameters invocation:

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

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

This way of using checks that the max parameter is bigger than min. Otherwise, we’ll get an IllegalArgumentException. However, it doesn’t check if we work with positive or negative numbers. So, any of the parameters can be negative. Also, we have available one- and zero-parameter invocations. Those work in the same way as we have described before.

这种使用方式可以检查max参数是否大于min。否则,我们会得到一个IllegalArgumentException然而,它并不检查我们是否对正数或负数进行处理。因此,任何参数都可以是负数。此外,我们还有可用的单参数和零参数调用。这些工作方式与我们之前描述的相同。

We have available the ints methods, too. This means that we can easily get a stream of int values. To clarify, we can choose to have a limited or unlimited stream. For a limited stream, we can set the top and bottom for the number generation range:

我们也有可用的int方法。这意味着我们可以很容易地得到一个int值的流。为了说明问题,我们可以选择有限的或无限的流。对于一个有限的流,我们可以为数字生成范围设置顶部和底部。

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

2.5. java.security.SecureRandom

2.5.java.security.SecureRandom

If we have security-sensitive applications, we should consider using SecureRandom. This is a cryptographically strong generator. Default-constructed instances don’t use cryptographically random seeds. So, we should either:

如果我们有安全敏感的应用程序,我们应该考虑使用SecureRandom.这是一个密码学上很强的发生器。默认构建的实例不使用加密的随机种子。所以,我们应该要么。

  • Set the seed — consequently, the seed will be unpredictable
  • Set the java.util.secureRandomSeed system property to true

This class inherits from java.util.Random. So, we have available all the methods we saw above. For example, if we need to get any of the int values, then we’ll call nextInt without parameters:

这个类继承于java.util.Random。所以,我们有上面看到的所有方法可用。例如,如果我们需要获得任何一个int值,那么我们就调用nextInt,不需要参数。

SecureRandom secureRandom = new SecureRandom();
int randomWithSecureRandom = secureRandom.nextInt();

On the other hand, if we need to set the range, we can call it with the bound parameter:

另一方面,如果我们需要设置范围,我们可以用bound参数调用它。

int randomWithSecureRandomWithinARange = secureRandom.nextInt(max - min) + min;

We must remember that this way of using it throws IllegalArgumentException if the parameter is not bigger than zero.

我们必须记住,这种使用方式会抛出IllegalArgumentException,如果参数不大于0。

3. Using Third-Party APIs

3.使用第三方API

As we have seen, Java provides us with a lot of classes and methods for generating random numbers. However, there are also third-party APIs for this purpose.

正如我们所见,Java为我们提供了很多生成随机数的类和方法。然而,也有第三方的API用于这一目的。

We’re going to take a look at some of them.

我们来看看其中的一些。

3.1. org.apache.commons.math3.random.RandomDataGenerator

3.1.org.apache.commons.math3.random.RandomDataGenerator

There are a lot of generators in the commons mathematics library from the Apache Commons project. The easiest, and probably the most useful, is the RandomDataGenerator. It uses the Well19937c algorithm for the random generation. However, we can provide our algorithm implementation.

在Apache Commons项目的commons数学库中有很多生成器。最简单的,也可能是最有用的,是RandomDataGenerator。它使用Well19937c算法进行随机生成。然而,我们可以提供我们的算法实现。

Let’s see how to use it. Firstly, we have to add dependency:

让我们看看如何使用它。首先,我们必须添加依赖性。

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

The latest version of commons-math3 can be found on Maven Central.

最新版本的commons-math3可以在Maven Central上找到。

Then we can start working with it:

然后我们就可以开始工作了。

RandomDataGenerator randomDataGenerator = new RandomDataGenerator();
int randomWithRandomDataGenerator = randomDataGenerator.nextInt(min, max);

3.2. it.unimi.dsi.util.XoRoShiRo128PlusRandom

3.2. it.unimi.dsi.util.XoRoShiRo128PlusRandom

Certainly, this is one of the fastest random number generator implementations. It has been developed at the Information Sciences Department of the Milan University.

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

The library is also available at Maven Central repositories. So, let’s add the dependency:

该库在Maven Central资源库中也有。因此,我们来添加该依赖性。

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

This generator inherits from java.util.Random. However, if we take a look at the JavaDoc, we realize that there’s only one way of using it —  through the nextInt method. Above all, this method is only available with the zero- and one-parameter invocations. Any of the other invocations will directly use the java.util.Random methods.

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

For example, if we want to get a random number within a range, we would write:

例如,如果我们想在一个范围内获得一个随机数,我们就写。

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

4. Conclusion

4.总结

There are several ways to implement random number generation. However, there is no best way. Consequently, we should choose the one that best suits our needs.

有几种方法可以实现随机数的生成。然而,没有最好的方法。因此,我们应该选择最适合我们需求的方式。

The full example can be found over on GitHub.

完整的例子可以在GitHub上找到over