Generate random numbers with Java
To generate random numbers in Java we have two options. On the one hand, we can use Math.random(), and on the other the java.util.Random class. The first is easier and faster to use. The second gives us more options.
We will also see some interesting cases, for example, generating random numbers without repetition or generating a random characters sequence (a String).
If any questions about the subject or java in general, I usually answer in the java forum.
Math.random()
The call to Math.random() returns a random number between 0.0 and 1.0, excluding this last value, that is, it can return 0.346442, 0.2344234, 0.98345,...
Generate a random number from 1 to 10
In many of our applications, this range of values is not what we want. For example, if we want to simulate a dice roll, we want numbers between 1 and 6 without decimals. Another typical case is to generate a random number from 1 to 10. We must do some math to obtain what we want.
First of all, we look at how many values we want. In our case, from 1 to 10, there are 10 values: from 1 to 10 both included. Then we must multiply Math.random() by 10. If we wanted values between any two numbers both included, for example, from 5 to 10, the count would be (maximum-minimum)+1, that is, (10- 5)+1 = 6, we would multiply by 6. In our example from 1 to 10, it would be (10-1)+1 = 10.
Math.random()*10 // This generates random numbers between 0.0 and 10.0, excluding 10.0.
Since our first value is 1, we add 1 to the result. In the event that we wanted between 5 and 10, we would have to add 5, that is, the minimum value.
Math.random()*10 // This generate random numbers between 0.0 and 11.0, excluding 11.0.
Finally, to get an integer, we remove the decimals using the class Math.floor() and cast to int.
int randomNumber = (int)Math.floor(Math.random()*10+1);
In general, to get an integer between M and N with M less than N and both included, we must use this formula
int randomValue = (int) Math.floor(Math.random()*(N-M+1)+M); // Value between M and N, both included.
If we don't want an integer value but double, the formula is without the +1
double valorAleatorio = Math.random()*(N-M)+M;
but remember, the value N is excluded and will never come out.
Class java.util.Random
The java.util.Random class also allows us to generate random numbers. We must instantiate it, unlike the Math.random() method. In return, we will have many more possibilities.
We can either use a parameterless constructor or pass a seed to it. If we instantiate the class several times with the same seed, we will always have the same sequence of random numbers.
Random r1 = new Random();
Random r2 = new Random(4234);
Random r3 = new Random(4234); // r2 and r3 will generate the same sequence of random numbers.
The easiest way is to use the parameterless constructor, which will normally give different sequences on each instance. However, one way to get a seed that is different every time we run our program might be to get the current time in milliseconds with System.currentTimeMillis(), which will generate different random numbers unless we instantiate it right in the same instant of time.
With this class, once instantiated, our random number problem from 1 to 10 is much simpler, using the nextInt(int n) method, which returns a value between 0 and n, excluding n
Random r = new Random();
int valorDado = r.nextInt(10)+1; // Between 0 and 10 excluded, plus 1, that is, from 1 to 10 both included.
We also have functions that generate a random value following a Gaussian curve or that fill an array with random bytes. And of course, the nextDouble() which returns a random value between 0.0 and 1.0, excluding the latter.
Random numbers without repetition
If we want to generate a series of random numbers without repeating any, depending on our specific problem, we have two ways to do it.
Randomly pick and remove from a set
Imagine that we are playing a card game and we want to distribute the cards randomly among the players. To avoid repetitions, the algorithm that we can use can be like the following
- Assuming a deck of 52 cards, we put the numbers from 1 to 52 in an array/list. Each number represents one of the cards, for example, 1 the Ace of Diamonds, 2 the two of Diamonds, ... 13 the King of Diamonds, 14 the Ace of Hearts, ... and so on.
- Randomly choose a valid index from the array or list to extract the card and remove it from the array/list. The size of the array/list will be reduced by 1. It goes, for example, from 52 cards to 51 cards once we have drawn the first one.
In this way, we simulate the deck of cards from which we are extracting cards. The java code for this might resemble the following
// We put in a list the numbers from 1 to 52.
List<Integer> numbers = new ArrayList<>(40);
for (int i=1;i<53;i++){
numbers.add(i);
}
// We instantiate the class Random
Random random = new Random();
// As long as there are cards left in the deck (in the list of numbers)
while (numbers.size()>1){
// We choose a random index, between 0 and the number of cards left to draw
int randomIndex = random.nextInt(numbers.size());
// We give the card to the player (we print the number on the screen)
System.out.println("Not Repeated Random Number "+numbers.get(randomIndex));
// And we remove the card from the deck (we delete it from the list)
numbers.remove(randomIndex);
}
Of course, if they are not cards, but numbers, simply put in the list the numbers you want to be able to come out.
This algorithm is valid as long as the possible set of numbers to draw does not take up too much memory. If you need all possible integers without repetition, this algorithm may not work for you.
Store generated random numbers
The other alternative is to generate random numbers and store them in a java Set
set. We generate a new random number and before we output the number to the screen (or do whatever we have to do with it), we must check if it already exists in the set. If it exists, we discard it and generate another one. If it doesn't exist, we use it and add it to the set.
The java code may be similar to the following
// Set of numbers already used
Set<Integer> alreadyUsedNumbers = new HashSet<>();
// Let's generate 10 random numbers without repetition
while (alreadyUsedNumbers.size()<10) {
// Random number between 0 and 40, excluding 40.
int randomNumber = random.nextInt(40);
// If we haven't used it already, we use it and put it in the used set.
if (!alreadyUsedNumbers.contains(randomNumber)){
System.out.println("Not Repeated Random Number "+randomNumber);
alreadyUsedNumbers.add(randomNumber);
}
}
This algorithm also has its drawbacks. We may have the bad luck that many already used random numbers are generated and we have to iterate many times until we obtain a number that have not already used. In the code above there is a possibility, possible but not likely, that the loop will never end, or take half an hour just to get 10 numbers. This will be more likely the more numbers we want to draw and the fewer numbers there are to choose from. In the example, we draw 10 numbers without repetition (loop of 10 numbers) from a possible set of 40 numbers (nextInt(40)
). So in the end we have a 1 in 4 chance of getting a number already used.
Random text string
Let's look at a couple of possibilities to generate a random text string.
Pick characters randomly from an array
Generating a random text string is a variant of what we just saw of choosing numbers from a list. We put in an array of characters the characters that interest us for our random string. Then we just have to choose random indices within that array. The java code may look like the following
// The characters of interest in an array of char.
char [] chars = "0123456789abcdefghijklmnopqrstuvwxyz".toCharArray();
// Length of char array.
int charsLength = chars.length;
// Instantiate the class Random
Random random = new Random();
// A StringBuffer to compose the random string efficiently
StringBuffer buffer = new StringBuffer();
// Loop to choose a string of 10 characters at random
for (int i=0;i<10;i++){
// add a random character from the array to the buffer
buffer.append(chars[random.nextInt(charsLength)]);
}
// And we only have to do something with the chain
System.out.println("Random String " + buffer.toString());
Of course, we can put in the array of characters those of interest (uppercase, lowercase, special characters or whatever we want). If the array is too long to do it by hand, we can make loops or something to fill it.
Or we can also use the ascii values of the characters. For example, the uppercase letters from A to Z carry the ascii codes from 65 to 90, so choosing random uppercase letters is the same of choosing a random number between 65 and 90, inclusive.
Generate random session identifiers
A somewhat more elaborate mechanism is used to generate the session ids of certain applications. When a user enters their name and password on a website, the web server generates a random session identifier, which is usually a long string of letters and numbers. In the following requests, the browser always sends this number, so that the server knows that the user has already been authenticated. This avoids having to send a username and password in each request. The mechanism in java can be something like the following
- The java class
BigInteger
has a method to generate a random number with the number of bits that we tell it. - We get that random number in base 32 (in base 32, every 5 bits become a digit/letter from 0 to 9 and from 'a' to 'v' (w,x,y and z will not come out).
- So our
BigInteger
has to have as many bits as letters we want in the identifier multiplied by 5.
For example, the following code java outputs a random string of 10 characters
// The famous Random
Random random = new Random();
// A BigInteger, 50 bits (10 characters * 5 bits per character)
System.out.println("Random String " + new BigInteger(50, random).toString(32));
We use the constructor of BigInteger
which is passed the number of bits (50 bits = 10 desired characters in our string * 5 bits per character) and an instance of Random
. We use the BigInteger.toString(32)
method to convert it to a base 32 String
.
For session id, something stronger is needed. A minimum of 128 bits is usually requested (which we must still round to 130 so that it is a multiple of 5) and a more random random number generator is used, the SecureRandom
class, which is more expensive than instantiate.
One downside of this method is that a zero or more can be output as the first character... and in numbers the leading zeros are not printed, so in this case less than 10 characters would be output.
Stream of random numbers
Since Java 8, the Random
class has several ints()
methods that return an IntStream
or random integer stream. The code to generate random numbers using this method might look like the following:
// Instantiate class Random
Random random = new Random();
// Get IntStream. The IntStream will have 10 random numbers
// between 1 and 7, excluding 7. Wow, the typical roll of the dice from 1 to 6.
IntStream intStream = random.ints(10, 1, 7);
// Iterator to get the numbers
Iterator iterator = intStream.iterator();
// We get the random numbers on the screen, in a loop.
while (iterator.hasNext()){
System.out.println("Random Number "+iterator.next());
}
The ints()
method has several variants depending on the number of parameters we pass to it. In the example we have chosen the most complete, in which we give how many random numbers we want, the lowest number (1) and the highest number (7, excluded). If we don't put the first parameter, the flow of integers will be infinite, we can request as many as we want. If we do not put minimum and maximum any integer can come out, no matter how big it is.
The class IntStream has interesting methods for generating random number or integer streams in various ways.
If we want to loop through our IntStream
more Java 8 style, we can use the IntStream.forEach()
method as follows
Random random = new Random();
intStream = random.ints(10, 1, 7);
intStream.forEach(value ->
System.out.println("Random Number "+value)
};
Of course, the IntStream
must be limited, or we will never finish writing random numbers to the screen.
Links
- In the java api, the class Random
- From Mykong's blog, Generate Random Integers in a Range