Chapters
In this tutorial, we're going to discuss different ways of generating random numbers in java.
Method Form:
This method is located in java.lang.Math package. This method returns a double value with a positive sign, greater than or equal to 0.0 and less than 1.0. Returned values are chosen pseudorandomly with (approximately) uniform distribution from that range.
This example demonstrates Math.random().
Instance of Random is used to generate a stream of pseudorandom numbers. 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. More information can be read in the documentation.
This example demonstrates the Random class.
Next, this example demonstrates random with explicit seed.
Note: You should be knowledgeable about Stream class to understand the methods that I'm gonna demonstrate next.
This example demonstrates ints() method.
Next, this example demonstrates ints(int randomNumberOrigin, int randomNumberBound).
Next, this example demonstrates ints(long streamSize).
Next, this example demonstrates ints(long streamSize, int randomNumberOrigin, int randomNumberBound).
This example is applicable to
Note: Most method of this class is identical to the method of Random class. Better read the Random class topic first before reading this topic.
ThreadLocalRandom is a random number generator (with period 2^64) isolated to the current thread. Like the global Random generator used by the Math class, a ThreadLocalRandom is initialized with an internally generated seed that may not otherwise be modified. When applicable, use of ThreadLocalRandom rather than shared Random objects in concurrent programs will typically encounter much less overhead and contention.
Use of ThreadLocalRandom is particularly appropriate when multiple tasks (for example, each a ForkJoinTask) use random numbers in parallel in thread pools. In Random class, we can use the method
As the description above says, using ThreadLocalRandom rather than shared Random objects in concurrent programs will typically encounter much less overhead and contention.
Usages of this class should typically be of the form: ThreadLocalRandom.current().nextX(...) (where X is Int, Long, etc). When all usages are of this form, it is never possible to accidentally share a ThreadLocalRandom across multiple threads.
This example demonstrates ThreadLocalRandom.
SplittableRandom is a generator of uniform pseudorandom values (with period 2^64) applicable for use in (among other contexts) isolated parallel computations that may generate subtasks. This class can split random-generating task into multiple subtasks by using the
There are important pieces of information in the documentation that I didn't put here. You should read it. This example demonstrates SplittableRandom.
Previous random generators are cryptographically weak. SecureRandom uses different types of algorithms that are cryptographically strong. If you need a secure random generator in an application like authenticator app, consider using SecureRandom.
This class provides a cryptographically strong random number generator (RNG). A cryptographically strong random number minimally complies with the statistical random number generator tests specified in FIPS 140-2, Security Requirements for Cryptographic Modules, section 4.9.1. Additionally, SecureRandom must produce non-deterministic output.
Therefore any seed material passed to a SecureRandom object must be unpredictable, and all SecureRandom output sequences must be cryptographically strong, as described in RFC 4086: Randomness Requirements for Security. SecureRandom objects are safe for use by multiple concurrent threads. More information can be read in the documentation.
This example demonstrates SecureRandom.
One of the best usage of
Java Tutorial: Generating Random Numbers
In this tutorial, we're going to discuss different ways of generating random numbers in java.
Math.random() Method
Method Form:
public static double random()
This method is located in java.lang.Math package. This method returns a double value with a positive sign, greater than or equal to 0.0 and less than 1.0. Returned values are chosen pseudorandomly with (approximately) uniform distribution from that range.
This example demonstrates Math.random().
public class SampleClass{ public static void main(String[] args){ double d = Math.random(); String s = String.format("%.1f",d); System.out.println(s); //with multiplier d = Math.random() * 2; s = String.format("%.1f",d); System.out.println(s); } } Result(may vary) 0.6 1.5
java.util.Random Class
Instance of Random is used to generate a stream of pseudorandom numbers. 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. More information can be read in the documentation.
This example demonstrates the Random class.
import java.util.Random; public class SampleClass{ public static void main(String[] args){ Random random = new Random(); System.out.println("Ints"); for(int i = 0; i < 3; i++) System.out.println(random.nextInt() + " "); System.out.println(); System.out.println("Doubles"); for(int i = 0; i < 3; i++) System.out.printf("%.2f%n",random.nextDouble()); System.out.println(); System.out.println("Guassian"); for(int i = 0; i < 3; i++) System.out.printf("%.2f%n",random.nextGaussian()); } } Result(may vary) Ints -612467063 1655395407 2107210140 Doubles 0.46 0.40 0.25 Gaussian 0.90 -2.14 0.77In the example above, I used this constructor of Random:
new Random()
. This constructor will automatically generate seeds for us everytime we invoke methods that starts random computation like nextInt()
. nextInt()
returns a randomed integer number. All 2^32 possible int values are produced with (approximately) equal probability.
nextDouble()
returns a uniformly distributed double value between 0.0 and 1.0 from this random number generator's sequence. nextGaussian()
Returns a Gaussian(normal distribution) distributed double value with mean 0.0 and standard deviation 1.0 from this random number generator's sequence.
Next, this example demonstrates random with explicit seed.
import java.util.Random; public class SampleClass{ public static void main(String[] args){ Random random = new Random(1); System.out.println ("Initial random: " + random.nextInt()); for(int i = 1; i <= 5; i++){ random.setSeed(i); System.out.println("Random: " + random.nextInt()); } } } Result(may vary) Initial random: -1155869325 Random: -1155869325 Random: -1154715079 Random: -1155099828 Random: -1157023572 Random: -1157408321Initial random and the first random are equal because they have the same seed which is 1. Remember that the algorithm used in the Random class is a pseudorandom governed by a mathematical formula.
Note: You should be knowledgeable about Stream class to understand the methods that I'm gonna demonstrate next.
nextInt()
method have second form where we can put a limit or bounds to the returned random value. Take a look at this example.
import java.util.Random; public class SampleClass{ public static void main(String[] args){ Random random = new Random(); System.out.println("set1"); //random between 0-9 for(int i = 0; i < 3; i++) System.out.println(random.nextInt(10) + " "); System.out.println("set2"); //random between 1-10 for(int i = 0; i < 3; i++) System.out.println((random.nextInt(10)+1) + " "); System.out.println("set3"); //random between 0 to -10 for(int i = 0; i < 3; i++) System.out.println((random.nextInt(11)+(-10)) + " "); } } Result(may vary) Set1 3 8 1 Set2 8 1 10 Set3 -1 -10 -5Remember that the number in the parameter is exclusive. It means that the given value is not included in the range. For example,
random.nextInt(10)
has a range from 0-9 not 0-10. Random class has methods that return a specific variants of Stream class. doubles()
, ints()
and longs()
return DoubleStream, IntStream and LongStream respectively.
This example demonstrates ints() method.
import java.util.Random; import java.util.Optional; public class SampleClass{ public static void main(String[] args){ Random random = new Random(); int num = random .ints() .findFirst() .getAsInt(); System.out.println(num); } } Result(may vary) -1994793268
ints()
method returns an effectively unlimited stream of pseudorandom int values. Use short-circuiting operations to stop infinite stream like the example above. findFirst()
is a short-circuiting terminal operation. The example above is applicable to doubles()
and longs()
with few modifications.
Next, this example demonstrates ints(int randomNumberOrigin, int randomNumberBound).
import java.util.Random; import java.util.Optional; public class SampleClass{ public static void main(String[] args){ Random random = new Random(); int num = random .ints(0,11) .findAny() .getAsInt(); System.out.println(num); } } Result(may vary) 5Just like the example above, the returned stream here is infinite.
randomNumberBound
is exclusive. This means that the exact range is between randomNumberOrigin-(randomNumberBound-1). This example is applicable to doubles(double randomNumberOrigin, double randomNumberBound)
and longs(long randomNumberOrigin, long randomNumberBound)
with few modifications.
Next, this example demonstrates ints(long streamSize).
import java.util.Random; public class SampleClass{ public static void main(String[] args){ Random random = new Random(); random .ints(10) .filter((t) -> { if(t % 2 == 0) return true; else return false; }) .forEach(System.out::println); } } Result(may vary) 1162373228 -483124408 -2060536350 351896346 1394074158Unlike in the two previous examples before this example above, the returned stream here has finite elements. Thus, we are not required to use short-circuiting operations.
streamSize
is the size of the returned stream. This example is applicable to doubles(long streamSize)
and longs(long streamSize)
.
Next, this example demonstrates ints(long streamSize, int randomNumberOrigin, int randomNumberBound).
import java.util.Random; public class SampleClass{ public static void main(String[] args){ Random random = new Random(); random .ints(5, 20, 41) .forEach(System.out::println); } } Result(may vary) 27 21 28 33 28Just like the example that preceded this example above, the returned stream here is finite.
randomNumberBound
is exclusive. This means that the exact range is between randomNumberOrigin-(randomNumberBound-1). ints(long streamSize, int randomNumberOrigin, int randomNumberBound)
is a combination of ints(int randomNumberOrigin, int randomNumberBound)
and ints(long streamSize)
.
This example is applicable to
doubles(long streamSize, double randomNumberOrigin, double randomNumberBound)
and longs(long streamSize, long randomNumberOrigin, long randomNumberBound)
.
java.util.concurrent.ThreadLocalRandom Class
Note: Most method of this class is identical to the method of Random class. Better read the Random class topic first before reading this topic.
ThreadLocalRandom is a random number generator (with period 2^64) isolated to the current thread. Like the global Random generator used by the Math class, a ThreadLocalRandom is initialized with an internally generated seed that may not otherwise be modified. When applicable, use of ThreadLocalRandom rather than shared Random objects in concurrent programs will typically encounter much less overhead and contention.
Use of ThreadLocalRandom is particularly appropriate when multiple tasks (for example, each a ForkJoinTask) use random numbers in parallel in thread pools. In Random class, we can use the method
next(int bits)
to get an integer random number that also atomatically updates its seed. Although, contention likely occurs if multiple threads access next(int bits)
.
As the description above says, using ThreadLocalRandom rather than shared Random objects in concurrent programs will typically encounter much less overhead and contention.
Usages of this class should typically be of the form: ThreadLocalRandom.current().nextX(...) (where X is Int, Long, etc). When all usages are of this form, it is never possible to accidentally share a ThreadLocalRandom across multiple threads.
This example demonstrates ThreadLocalRandom.
import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class SampleClass{ public static void main(String[] args){ System.out.println (Thread.currentThread().getName() + " | " + ThreadLocalRandom.current().nextInt(10)); ExecutorService es = Executors.newFixedThreadPool(4); for(int i = 0; i < 4; i++) es.execute(() -> { System.out.println (Thread.currentThread().getName() + " | " + ThreadLocalRandom.current().nextInt(10)); }); es.shutdown(); } } Result(may vary) main | 7 pool-1-thread-1: 0 pool-1-thread-3: 9 pool-1-thread-2: 1 pool-1-thread-4: 7
current()
method returns the current thread's ThreadLocalRandom object. Methods of this object should be called only by the current thread, not by other threads. As the description implies, every thread has a ThreadLocalRandom object.
java.util.SplittableRandom Class
SplittableRandom is a generator of uniform pseudorandom values (with period 2^64) applicable for use in (among other contexts) isolated parallel computations that may generate subtasks. This class can split random-generating task into multiple subtasks by using the
split()
method.
There are important pieces of information in the documentation that I didn't put here. You should read it. This example demonstrates SplittableRandom.
import java.util.concurrent.ForkJoinPool; import java.util.concurrent.RecursiveTask; import java.util.concurrent.atomic.AtomicInteger; import java.util.SplittableRandom; public class SampleClass{ public static void main(String[] args){ System.out.println("\nCreating "+ "ForkJoinPool..."); ForkJoinPool fjp = ForkJoinPool.commonPool(); int result = fjp.invoke(new Randomize(new SplittableRandom())); System.out.println("Sum: " + result); } } class Randomize extends RecursiveTask<Integer>{ private final SplittableRandom splitTask; private static final AtomicInteger ai = new AtomicInteger(0); Randomize(SplittableRandom splitTask){ this.splitTask = splitTask; } protected Integer compute(){ Integer result = 0; if(ai.incrementAndGet() < 3){ Randomize s1 = new Randomize(splitTask.split()); s1.fork(); int rand = splitTask.ints(10, 20).findAny().getAsInt(); Randomize s2 = new Randomize(splitTask); result = rand + s2.compute() + s1.join(); System.out.println(Thread. currentThread().getName() + " | Partial Result | " + rand); } else{ result = splitTask.ints(10, 20).findAny().getAsInt(); System.out.println(Thread. currentThread().getName() + " | Partial Result | " + result); } return result; } } Result(may vary) Creating ForkJoinPool... FokJoinPool.commonPool-worker-1 | Partial Result | 17 FokJoinPool.commonPool-worker-2 | Partial Result | 15 main | Partial Result | 17 FokJoinPool.commonPool-worker-1 | Partial Result | 11 main | Partial Result | 14 Sum: 74If you want to split a specific SplittableRandom, use this form of split:
split(RandomGenerator.SplittableGenerator source)
splits()
is a new method added to java 17 that returns new pseudorandom number generators, each of which implements the RandomGenerator.SplittableGenerator interface. This method has four forms. Two of them returns an infinite stream of pseudorandom number generators. The remaining two returns a finite stream. You can read them in the documentation.
java.security.SecureRandom Class
Previous random generators are cryptographically weak. SecureRandom uses different types of algorithms that are cryptographically strong. If you need a secure random generator in an application like authenticator app, consider using SecureRandom.
This class provides a cryptographically strong random number generator (RNG). A cryptographically strong random number minimally complies with the statistical random number generator tests specified in FIPS 140-2, Security Requirements for Cryptographic Modules, section 4.9.1. Additionally, SecureRandom must produce non-deterministic output.
Therefore any seed material passed to a SecureRandom object must be unpredictable, and all SecureRandom output sequences must be cryptographically strong, as described in RFC 4086: Randomness Requirements for Security. SecureRandom objects are safe for use by multiple concurrent threads. More information can be read in the documentation.
This example demonstrates SecureRandom.
import java.security.SecureRandom; public class SampleClass{ public static void main(String[] args){ SecureRandom random = new SecureRandom(); System.out.println("Algorithm: " + random.getAlgorithm()); random .ints(5, 20, 41) .forEach(System.out::println); } } Result(may vary) Algorithm: DRBG 27 26 22 31 22In java 17, when
SecureRandom()
constructor is used, the default alrogithm is DRBG or Deterministic Random Big Generator. SecureRandom can use different types of algorithm which can be seen in this article.
One of the best usage of
SecureRandom
is to generate random hashes. This example demonstrates generating salt.. One of the usage of salt is to secure passwords.
import java.math.BigInteger; import java.security.SecureRandom; import java.security.NoSuchAlgorithmException; public class SampleClass{ public static void main(String[] args) throws NoSuchAlgorithmException{ SecureRandom random = SecureRandom.getInstance("SHA1PRNG"); System.out.println("Algorithm: " + random.getAlgorithm()); byte[] salt = new byte[16]; random.nextBytes(salt); System.out.println("Salt"); System.out.println( new BigInteger(1, salt).toString(16)); } } Result(may vary) Algorithm: SHA1PRNG Salt d66d227b210c...Use
getInstance(String algorithm)
to use other algorithms. This method returns a SecureRandom object that implements the specified Random Number Generator (RNG) algorithm. getInstance()
has many forms that can be seen in the documentation.
nextBytes(byte[] bytes)
generates random bytes based on the length of the byte array argument and put those generated random bytes in the array.
No comments:
Post a Comment