## 1. Overview

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

## 2. Using Java API

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

### 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*:

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

### 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:

```
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:

`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*.

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

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

`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*

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:

- 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:

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

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

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

### 2.4. *java.util.SplittableRandom*

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

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.

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

```
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.

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:

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

### 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:

- 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:

```
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:

`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.

## 3. Using Third-Party APIs

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.

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

### 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.

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.

Then we can start working with it:

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

### 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:

```
<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.

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

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.