**Get started with Spring 5 and Spring Boot 2, through the ***Learn Spring* course:

*Learn Spring*course:

Last modified: September 28, 2022

In this quick tutorial, we'll learn how to generate random numbers with no duplicates using core Java classes. **First, we'll implement a couple of solutions from scratch, then take advantage of Java 8+ features for a more extensible approach.**

If the range of numbers we need is small, we can keep adding sequential numbers to a list until we reach size *n*. **Then, we call Collections.shuffle(), which has linear time complexity. After that, we'll end up with a randomized list of unique numbers.** Let's create a utility class to generate and use those numbers:

```
public class UniqueRng implements Iterator<Integer> {
private List<Integer> numbers = new ArrayList<>();
public UniqueRng(int n) {
for (int i = 1; i <= n; i++) {
numbers.add(i);
}
Collections.shuffle(numbers);
}
}
```

After constructing our object, we'll have numbers from one to *size* in random order. **Notice we're implementing Iterator, so we'll get a random number every time we call next().** Also, we can check if we have numbers left with

```
@Override
public Integer next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
return numbers.remove(0);
}
@Override
public boolean hasNext() {
return !numbers.isEmpty();
}
```

Consequently, *remove()* returns the first removed item from the list. **Similarly, if we hadn't shuffled our collection, we could pass it a random index.** But, shuffling at construction time has the advantage of letting us know the whole sequence in advance.

To use it, we just choose how many numbers we want and consume them:

```
UniqueRng rng = new UniqueRng(5);
while (rng.hasNext()) {
System.out.print(rng.next() + " ");
}
```

This could result in output like:

`4 1 2 5 3`

We need a different strategy if we want a more extensive range of numbers, only using a few of them. First, we cannot rely on adding random numbers to an *ArrayList* because that could generate duplicates. **So, we'll use a Set because it guarantees unique items.** Then, we'll use the

**This time, we'll add elements to our set in a loop until we reach size. Also, we'll use Random to generate random integers from zero to max:**

```
public class BigUniqueRng implements Iterator<Integer> {
private Random random = new Random();
private Set<Integer> generated = new LinkedHashSet<>();
public BigUniqueRng(int size, int max) {
while (generated.size() < size) {
Integer next = random.nextInt(max);
generated.add(next);
}
}
}
```

Note we don't need to check if a number already exists in our set because *add()* does this. **Now, since we can't remove items by index, we need the help of an Iterator to implement next():**

```
public Integer next() {
Iterator<Integer> iterator = generated.iterator();
Integer next = iterator.next();
iterator.remove();
return next;
}
```

While custom implementations are more reusable, we can create a solution using only *Stream*s. **Starting with Java 8, Random has an ints() method that returns an IntStream. We can stream it and impose the same requisites from earlier, like a range and a limit.** Let's combine these features and

```
Set<Integer> set = new Random().ints(-5, 15)
.distinct()
.limit(5)
.boxed()
.collect(Collectors.toSet());
```

The traversed set could yield output like:

`-5 13 9 -4 14`

With *ints(),* it's even simpler to have a range starting from a negative integer. **But, we must be careful not to end up with an infinite stream, which would happen if we didn't call limit(), for example.**

In this article, we wrote a couple of solutions to generate random numbers with no duplicates in two scenarios. First, we've made those classes iterable so we could easily consume them. Then, we created a more organic solution using streams.

And as always, the source code is available over on GitHub.

Login

0 Comments

Follow the Java Category

Follow the Java category to get regular info about the new articles and tutorials we publish here.