Getting random numbers in Java
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
Generating random numbers in Java is simple once you choose the right class for the job. The hard part is not syntax, but understanding the difference between ordinary pseudo-random values, thread-friendly generators, and cryptographically secure randomness.
Choose the Right Random API
Java gives you several ways to generate random values, and they are not interchangeable.
Use Random when you want a straightforward pseudo-random generator for simple programs, tests, or simulations. Use ThreadLocalRandom when many threads need random values without sharing a single generator. Use SecureRandom when the numbers protect passwords, tokens, session IDs, or anything security-sensitive.
That distinction matters because most “random” APIs in general-purpose programming are deterministic pseudo-random generators. They are excellent for games and sampling, but they are not safe for secrets.
Basic Random Numbers With Random
java.util.Random is the classic starting point. It can generate integers, booleans, doubles, and byte arrays.
A common beginner question is how to generate a value in a custom range. The key rule is that the upper bound is exclusive.
For an integer from min through max, inclusive:
If you forget that the upper bound is exclusive, your code will be off by one.
Better Concurrency With ThreadLocalRandom
In multi-threaded code, ThreadLocalRandom is usually a better default than sharing one Random instance. Each thread uses its own generator, which avoids unnecessary contention.
This is especially useful in web servers, background workers, and parallel simulations where many requests may need random values at the same time.
Use SecureRandom for Security
If the random value protects something important, use SecureRandom. Session tokens, password reset links, invitation codes, and cryptographic keys should never come from Random.
SecureRandom may be a little slower, but that is the correct tradeoff when unpredictability matters.
Streams and Modern Style
Java also supports generating streams of random values, which is useful when you want many numbers and plan to process them functionally.
This prints five integers from 1 through 6. Again, the upper bound is exclusive.
For data-heavy or simulation workloads, stream-based generation can make code cleaner and easier to combine with filtering, mapping, and aggregation.
Seeding and Reproducibility
Sometimes you do not want true unpredictability. In tests or simulations, repeatable output is often better because it makes failures reproducible.
Using the same seed produces the same sequence each time. That is useful for debugging randomized algorithms, but it is the opposite of what you want for security.
Common Pitfalls
The most common pitfall is using Random for security-sensitive tokens. That creates values that may be guessable enough to matter.
Another frequent issue is misunderstanding inclusive and exclusive bounds. nextInt(10) returns 0 through 9, not 1 through 10.
A third mistake is creating many new generators in a tight loop. Reusing the right generator is usually cleaner and more predictable.
Finally, some developers reach for Math.random() everywhere. It works for quick scripts, but it is less explicit than choosing Random, ThreadLocalRandom, or SecureRandom based on the real requirement.
Summary
- Use
Randomfor general pseudo-random values in ordinary application code. - Use
ThreadLocalRandomwhen many threads need random values efficiently. - Use
SecureRandomfor tokens, secrets, and cryptographic use cases. - Remember that integer upper bounds are exclusive unless you adjust the formula.
- Seeded generators are useful for reproducible tests, but not for secure randomness.

