In Java, generating random numbers has become more convenient and versatile with the introduction of new classes and methods in Java 8 and beyond.

This article explores how to generate random numbers in Java using Java 8’s standard library classes, including `Random`

, `SecureRandom`

, `SplittableRandom`

, and `ThreadLocalRandom`

.

## 1. Random Number Generator Classes and Their Usages

The

interface is the parent interface for all the random number generator classes and interfaces. It provides a way to ease the dependency injection mechanism in application code when we want to replace the generator class type from the configuration.*RandomGenerator*

The following classes implement this interface:

Class | Description | Key Characteristics |
---|---|---|

`Random` | Provides basic pseudo-random number generation capabilities. | Suitable for general non-cryptographic uses. |

`SecureRandom` | Provides cryptographically secure random number generation. | Suitable for cryptographic applications. |

`SplittableRandom` | Offers efficient parallel random number generation and splitting. | Designed for parallelism and good performance. |

`ThreadLocalRandom` | Provides thread-local random number generators for multi-threaded apps. | Ensures thread safety and efficiency in concurrent code. |

The *RandomGenerator* has the following sub-interfaces as well:

Interface | Description | Key Characteristics |
---|---|---|

`ArbitrarilyJumpableGenerator` | Represents a generator capable of arbitrary jumps. | Advanced control over the sequence of random numbers. |

`JumpableGenerator` | Represents a generator that can perform jumps. | Allows jumping ahead in the sequence. |

`LeapableGenerator` | Represents a generator that supports leaping. | Provides a method to leap ahead in the sequence. |

`SplittableGenerator` | Represents a generator designed for parallel generation. | Supports parallelism without contention. |

`StreamableGenerator` | Represents a generator that can produce streams. | Enables the generation of random number streams. |

As a rule, objects that implement the `RandomGenerator`

interface need not be thread-safe. It is recommended that multithreaded applications use either `ThreadLocalRandom`

or generators that implement the `SplittableGenerator`

or `JumpableGenerator`

interface.

Objects that implement `RandomGenerator`

are typically not cryptographically secure. Consider using `SecureRandom`

for such uses.

*Random*‘ for Pseudo-Random Numbers

2. Using ‘

Pseudo-Random NumberGenerator (PRNG) refers to an algorithm that uses mathematical formulas to produce sequences of random numbers.

The `java.util.Random`

class provides methods that can be used to **generate a stream of pseudo-random numbers or the next available random number** from the given generator’s sequence.

- If two instances of
`Random`

are created with the same seed, and the same sequence of method calls is made for each, they will generate and return identical sequences of numbers. - Instances of
`java.util.Random`

are threadsafe, but may encounter contention and consequent poor performance in a multi-threaded environment.`ThreadLocalRandom`

in such cases. - Instances of
`java.util.Random`

are not cryptographically secure. Use`SecureRandom`

to get a cryptographically secure pseudo-random number generator.

### 2.1. Generating Stream of Random Numbers

In the given example, we are creating a stream of random integers (IntStream) starting from 10 to 10,000. Then we take 6 numbers from the stream and print them in the console.

```
IntStream randomNumberStream = new Random().ints(10, 10000);
randomNumberStream
.limit(6)
.forEach(System.out::println);
```

Similarly, we can get the DoubleStream and LongStream as well.

### 2.2. Getting Next Random Number from the Generator

If we have an instance of the generator, we can it’s one of the *next…()* to get the next available random number either with only an upper bound or within range.

```
Random randomGenerator = new Random();
//Upper bound 10000
int r1 = random.nextInt(10_000);
//No upper bound
int r2 = random.nextInt();
//Within Range 0-100
int r2 = random.nextInt(0, 99);
```

Similarly, we have *nextBoolean()*, *nextDouble()*, *nextFloat()*, *nextLong()* and *nextGaussian()* methods for providing the desired random output type.

To get the most random and reliable results, do not create a new

`Random`

object for each new random number. Create one instance, and use it for generating a random everytime we need it in the application.

*SecureRandom*‘

3. Enhancing Security with ‘While `Random`

is suitable for many applications, but it’s not suitable for cryptographic purposes because the generated numbers can be predictable.

`SecureRandom`

class a cryptographically strong subclass of *Random*. This is used to generate highly random byte sequences generally to be used in security-related algorithms.

- We can use the constructor of
`SecureRandom`

class to provide the name of any specific algorithm we want to use. `SecureRandom`

objects are safe for use by multiple concurrent threads.

```
SecureRandom secureRandom = new SecureRandom("SHA1PRNG");
byte[] bytes = new byte[20];
secureRandom.nextBytes(bytes);
// Generate a random integer
int randomNumber = secureRandom.nextInt();
```

Read More: Generate Secure Password Hash

*SplittableRandom*‘

4. Parallelism with ‘Introduced in Java 8, SplittableRandom is a more advanced random number generator that allows for efficient parallel generation of random numbers. It can be especially useful in applications where multiple threads need independent random numbers without contention.

Its method `split()`

constructs and returns a new *SplittableRandom* instance that shares no mutable state with the current instance. However, the values collectively generated by the two generators have the same statistical properties as if these values were generated by a single thread.

Instances of *SplittableRandom* are *not* thread-safe. They are **designed to be split, not shared, across threads**.

```
SplittableRandom random = new SplittableRandom();
SplittableRandom splitted = random.split();
random.nextInt(10000)); //Thread 1
splitted.nextInt(10000)); //Thread 2
```

*ThreadLocalRandom*‘

5. Thread-Safe Randomness with ‘Java 7 introduced the ThreadLocalRandom class, which is designed to provide thread-local random number generators. Each thread contains its own generator, preventing contention between threads.

Instances of *ThreadLocalRandom* are not cryptographically secure. Consider using `SecureRandom`

in security-sensitive applications.

`int randomNumber = ThreadLocalRandom.current().nextInt();`

*ThreadLocalRandom* also provides more methods for generating random doubles, longs or Gaussian random numbers.

## 6. Math.random()

Many people will find Math.random() simpler to use. ** Math.random() returns a positive double number between 0.0 (inclusive) and 1.0 (exclusive).** If we need random numbers within a different range, we can scale and shift the result accordingly.

This is `static`

method to it will be created once for the application. When this method is first called, it creates a new pseudorandom number generator using statement * new java.util.Random()*. After that, for all calls, this

*Random*instance is used to provide random values pseudorandomly with (approximately) uniform distribution from that range.

This method is properly *synchronized* to work in a concurrent environment but is not suitable for cryptographic purposes.

`double randomValue = Math.random(); //0.19173629711153906`

## 7. Conclusion

As discussed above, Java provides a range of options to suit different requirements. We can choose from `Random`

for non-cryptographic uses, `SecureRandom`

for cryptographic applications, `SplittableRandom`

for parallelism, and `ThreadLocalRandom`

for thread safety.

Understanding these options and selecting the right one for the specific use case is essential to ensure the reliability and security of any Java application.

Happy Learning !!

## Comments