How to Generate Random Number in Java

โšก Smart Summary

Random numbers in Java come from four related standard library options, the Random class, Math.random, ThreadLocalRandom, and SecureRandom, each covering a different mix of speed, thread safety, and cryptographic strength for real applications.

  • ๐ŸŽฒ Random class: java.util.Random exposes nextInt, nextLong, nextDouble, and nextBoolean for common primitive types.
  • ๐Ÿงฎ Math.random: Math.random returns a double between 0.0 inclusive and 1.0 exclusive using a shared Random instance.
  • ๐ŸŽฏ Custom ranges: Pass a bound to nextInt or scale Math.random to generate values within any minimum and maximum.
  • ๐Ÿงต Thread safety: ThreadLocalRandom in java.util.concurrent gives each thread its own generator and outperforms a shared Random under contention.
  • ๐Ÿ” Security: SecureRandom in java.security produces cryptographically strong values for passwords, tokens, and session keys.
  • ๐ŸŒฑ Reproducibility: Seeding a Random with a fixed long makes tests and simulations deterministic across runs.

How to Generate Random Number in Java

Random numbers show up everywhere in Java, from unit-test data and dice-roll games to session tokens and shuffled decks. This tutorial explains how to generate random numbers in Java using every option in the standard library and how to pick the right one for the job.

Generate Random Number in Java

The Java standard library offers four common ways to generate a random number:

  • java.util.Random is the general-purpose class. It produces boolean, int, long, float, and double values through methods such as nextInt, nextLong, and nextDouble.
  • Math.random is a static helper that returns a double between 0.0 (inclusive) and 1.0 (exclusive) using a shared Random internally.
  • ThreadLocalRandom in java.util.concurrent gives each thread its own generator, so multiple threads do not contend on a single instance.
  • SecureRandom in java.security produces cryptographically strong pseudo-random numbers for passwords, session identifiers, and keys.

The sections below show how to generate ten random numbers with each approach.

Example: Generate Random Number Using Java Random Class

The first example uses java.util.Random to produce ten integers in the range 0 to 99 inclusive:

import java.util.Random;

public class RandomNumbers {
    public static void main(String[] args) {
        Random objGenerator = new Random();
        for (int iCount = 0; iCount < 10; iCount++) {
            int randomNumber = objGenerator.nextInt(100);
            System.out.println("Random No : " + randomNumber);
        }
    }
}

Output:

Random No : 17
Random No : 57
Random No : 73
Random No : 48
Random No : 68
Random No : 86
Random No : 34
Random No : 97
Random No : 73
Random No : 18

An instance of Random is created as objGenerator. The nextInt(int bound) method returns a value between 0 (inclusive) and the supplied bound (exclusive), so nextInt(100) yields values from 0 to 99. To make the sequence reproducible, pass a seed to the constructor, for example new Random(42); the same seed always produces the same sequence, which is useful in tests and simulations.

Example: Using Java Math.random

To generate ten random values in the range 0.0 to 1.0, call the static Math.random method inside a loop. This is the fastest way to obtain a random double without creating a generator object:

public class DemoRandom {
    public static void main(String[] args) {
        for (int xCount = 0; xCount < 10; xCount++) {
            System.out.println(Math.random());
        }
    }
}

Output:

0.46518450373334297
0.14859851177803485
0.5628391820492477
0.6323378498048606
0.1740198445692248
0.9140544122258946
0.9167350036262347
0.49251219841030147
0.7426056725722353
0.2039418871298877

Under the hood, Math.random creates a single static Random on first use and calls nextDouble on it. That single shared generator is fine for demos but becomes a bottleneck under heavy multithreaded load, which the next sections address.

Generate a Random Number in a Custom Range

Real programs usually need a random value inside a specific range, such as an integer between 1 and 6 for a dice roll or a double between 10.0 and 20.0 for a simulation. Two patterns cover almost every case.

Random integer between min and max (inclusive):

import java.util.Random;

public class RangeDemo {
    public static void main(String[] args) {
        Random rnd = new Random();
        int min = 1;
        int max = 6;
        // nextInt(max - min + 1) returns 0..(max-min), then shift by min
        int dice = rnd.nextInt(max - min + 1) + min;
        System.out.println("Dice roll : " + dice);
    }
}

Random double between min and max:

double min = 10.0;
double max = 20.0;
double value = min + (max - min) * Math.random();
System.out.println("Value : " + value);

Both patterns work by taking a value from the generator’s native range, scaling it to the width of the target range, and shifting it up by the minimum. If you are on Java 8 or later, the same result is available through the newer ints, longs, and doubles stream methods on Random, for example rnd.ints(10, 1, 7).forEach(System.out::println) for ten dice rolls.

ThreadLocalRandom for Multithreaded Code

A single shared Random is thread-safe but slow under contention because every thread has to synchronize on the same internal seed. ThreadLocalRandom, added in Java 7 and living in java.util.concurrent, gives each thread its own generator so there is no lock contention.

import java.util.concurrent.ThreadLocalRandom;

public class ThreadLocalDemo {
    public static void main(String[] args) {
        // random int in [1, 100]
        int i = ThreadLocalRandom.current().nextInt(1, 101);

        // random long in [1000, 5000]
        long l = ThreadLocalRandom.current().nextLong(1000L, 5001L);

        // random double in [0.0, 1.0)
        double d = ThreadLocalRandom.current().nextDouble();

        System.out.println(i + " " + l + " " + d);
    }
}

Use ThreadLocalRandom.current() inside worker threads, parallel streams, and any concurrent task. Note that setSeed throws UnsupportedOperationException, so seeding for reproducibility is not supported; if you need a fixed seed, stick with plain Random.

SecureRandom for Security-Sensitive Random Numbers

Instances of Random and ThreadLocalRandom are not cryptographically secure. Given a few output samples, an attacker can reconstruct the internal state and predict future values. For passwords, session tokens, salt values, and cryptographic keys, use java.security.SecureRandom instead. It draws seed material from the operating system entropy pool and produces values that resist prediction.

import java.security.SecureRandom;

public class SecureDemo {
    public static void main(String[] args) {
        SecureRandom secure = new SecureRandom();

        byte[] token = new byte[16];
        secure.nextBytes(token);          // 128-bit random token

        int otp = secure.nextInt(1_000_000); // 6-digit one-time code

        System.out.println("OTP : " + String.format("%06d", otp));
    }
}

SecureRandom is slower than Random because it uses stronger algorithms and richer seed material. Reserve it for security work and use the faster generators for games, simulations, and test data.

FAQs

Create a java.util.Random instance and call nextInt, nextLong, nextDouble, or nextBoolean. For a quick one-liner, use Math.random which returns a double between 0.0 and 1.0. Both approaches ship with the standard library.

Call random.nextInt(max – min + 1) + min for integers, or min + (max – min) * Math.random() for doubles. The formulas scale the generator range to your target window and shift by the minimum value.

Random is a full class with methods for many primitive types and supports seeding. Math.random is a static helper that returns a double between 0.0 and 1.0. Internally, Math.random calls a single shared Random instance.

Yes, but concurrent calls contend on the same internal seed, which slows heavily threaded code. Use ThreadLocalRandom.current() from java.util.concurrent to give each thread its own generator and remove that contention.

Pass a fixed long to the Random constructor, for example new Random(42), or call setSeed(42). The generator will produce the same sequence every run, which is essential for repeatable tests and simulations.

Use SecureRandom whenever the value must resist prediction, such as passwords, session tokens, salt values, one-time codes, and cryptographic keys. Plain Random is fast but predictable, so it is unsafe for security work.

Machine learning frameworks use pseudo-random generators to initialize weights, shuffle training data, and split validation sets. Fixing a seed makes experiments reproducible so teams can compare model runs and debug results reliably.

Yes. GitHub Copilot scaffolds Random, ThreadLocalRandom, and SecureRandom snippets, matching range-scaling formulas, and JUnit tests. Review each suggestion to confirm the chosen class fits the use case, especially for security-sensitive code.

Summarize this post with: