Random and SecureRandom in Java
Java has two main classes for random numbers. java.util.Random produces pseudo-random numbers: they look random but come from a formula, so the same seed gives the same sequence every time. It is fast and ideal for games, simulations and tests. java.security.SecureRandom produces numbers that are unpredictable, even to someone who has seen earlier values. It is used for passwords, tokens, keys and anything security-related. The basics of random numbers were introduced in "Generating Random Numbers"; in this lesson, you will learn both classes in depth.
Declaration
public class Random implements RandomGenerator, Serializable
public class SecureRandom extends RandomRandomGenerator (Java 17) is the common interface for all random number generators.
Methods of Random
| Method | Description |
|---|---|
nextInt() | It is used to get any random int. |
nextInt(bound) | It returns a number from 0 (included) to bound (excluded). |
nextInt(origin, bound) | It returns a number from origin to bound - 1 (Java 17). |
nextDouble() | It returns a double from 0.0 to just under 1.0. |
nextBoolean() | It returns true or false. |
nextGaussian() | It returns a number from a normal ("bell curve") distribution. |
nextBytes(byte[] b) | It fills an array with random bytes. |
ints(n, origin, bound) | It returns an IntStream of n random numbers. |
Example: Repeatable Random Numbers with a Seed
Let's see an example where two generators with the same seed give the same numbers.
import java.util.Random;
public class Seeded {
public static void main(String[] args) {
Random a = new Random(42);
Random b = new Random(42);
for (int i = 0; i < 3; i++) {
System.out.println(a.nextInt(100) + " " + b.nextInt(100));
}
Random dice = new Random(7);
System.out.println("Dice: " + dice.ints(5, 1, 7).boxed().toList());
System.out.println("Between 10 and 20: " + dice.nextInt(10, 21));
}
}30 30
63 63
48 48
Dice: [5, 3, 4, 5, 5]
Between 10 and 20: 14Explanation: new Random(42) starts the formula from the seed 42, so both generators produce exactly the same sequence. This makes tests and simulations repeatable. ints(5, 1, 7) gives a stream of five dice rolls from 1 to 6, and nextInt(10, 21) gives a number from 10 to 20.
SecureRandom
SecureRandom uses the operating system's source of randomness (such as hardware noise) so its output can't be predicted. It has the same methods as Random, because it extends it.
import java.security.SecureRandom;
import java.util.Base64;
public class Tokens {
public static void main(String[] args) {
SecureRandom secure = new SecureRandom();
byte[] bytes = new byte[24];
secure.nextBytes(bytes);
String token = Base64.getUrlEncoder().withoutPadding()
.encodeToString(bytes);
System.out.println("Reset token: " + token);
int otp = secure.nextInt(100_000, 1_000_000);
System.out.println("OTP: " + otp);
System.out.println("Algorithm: " + secure.getAlgorithm());
}
}Reset token: 6j3nabZpsoMUJj8Xcft9b4niBpk9_aFw
OTP: 536977
Algorithm: NativePRNGExplanation: 24 random bytes encoded with URL-safe Base64 make a 32-character token that is safe for a password-reset link. The six-digit OTP comes from nextInt(100000, 1000000). The algorithm name depends on the operating system.
Random vs SecureRandom
Random | SecureRandom | |
|---|---|---|
| Package | java.util | java.security |
| Predictable | Yes, from the seed | No |
| Speed | Fast | Slower |
| Repeatable with a seed | Yes | No (seeding only adds randomness) |
| Use for | Games, simulations, shuffling, tests | Passwords, tokens, OTPs, keys, salts |
Common Mistakes
Using Random or Math.random() for OTPs and tokens. Use SecureRandom.
Creating a new Random inside a loop. Create one and reuse it.
Expecting nextInt(10) to include 10. The bound is excluded.
Practice
- Easy: Simulate 1,000 coin flips with a seeded
Randomand print how many were heads. - Harder: Write a password generator with
SecureRandomthat builds a 12-character password with at least one upper-case letter, one digit and one symbol.
Key Takeaways
Was this tutorial helpful?