 Java, Spring and Web Development tutorials  1. Introduction
In this tutorial, we’ll learn how to create unique custom identifiers using plain Java and built-in alternatives, such as UUID.
2. Overview
Many modern-era applications require identifiers for tasks such as creating API keys and casting short links. To be valid, these identifiers must fulfill business constraints, such as minimum or maximum length or legal character set. The most critical constraints are usually that the identifier be random and unique.
Here, we’ll show how to generate a unique identifier with the following constraints:
- Its length must be less than n characters (where n is configurable).
- It must contain only English letters ([a-z] or [A-Z]) or numerals ([0-9]).
Then, we’ll cover built-in alternatives that are suitable for less restrictive constraints.
Our use case is to generate one identifier at a time, and not a batch with each call.
3. Random Generators: A Plain-Java Approach
As with any random generator, repetitions are always possible (collisions), even if the probability of generating a duplicate is low.
That’s why we must verify the uniqueness of an identifier before outputting it.
We check if it’s already in the identifier data store (such as a set, database, or any other persistent storage). If not, we save it to the store and return since we know it’s unique. Otherwise, we generate a new string and repeat the check.
3.1. Packages
Although we can use the package java.util.Random to generate random strings, the package java.security package.SecureRandom has the SecureRandom class. It provides a cryptographically strong, non-deterministic source of randomness, which is essential for generating non-guessable IDs.
3.2. String Generation
We define our source character set and its limit in our main class, UniqueIdGenerator:
public class UniqueIdGenerator {
private static final String ALPHANUMERIC_CHARACTERS =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
private static final SecureRandom random = new SecureRandom();
private static final idLength = 8; //Default to be overridden
public void setIdLength(int idLength) {}
public String generateUniqueId(Set<String> existingIds) {}
private String generateRandomString(int length) {}
}
The method generateUniqueId() returns a unique random identifier of the specified length. Internally, generateUniqueId() calls a helper method generateRandomString() using Java 8 Stream API that uses SecureRandom to pick characters from this string:
public String generateRandomString(int length) {
return random.ints(length, 0, ALPHANUMERIC_CHARACTERS.length())
.mapToObj(ALPHANUMERIC_CHARACTERS::charAt)
.map(Object::toString)
.collect(Collectors.joining());
}
We use random.ints(length, 0, ALPHANUMERIC_CHARACTERS.length()) to create an IntStream of length random integers in the range [0, the length of our character set (exclusive)]. Then, mapToObj(ALPHANUMERIC_CHARACTERS::charAt) maps each random integer to the character at that index in our ALPHANUMERIC_CHARACTERS string. Moving ahead, map(Object::toString) converts each Character to a String. Finally, we use collect(Collectors.joining()) to join all the single-character strings into a resulting string.
3.3. Uniqueness
The generateUniqueId() method uses a do-while loop, as we want to guarantee at least one attempt to generate an identifier. First, it creates a string by calling the method generateRandomString(). Then, it checks if the existingIds set already contains it. If so, the loop repeats. Otherwise, we know it’s unique and return it:
public String generateUniqueId(Set<String> existingIds) {
String newId;
do {
newId = generateRandomString(this.idLength);
} while (existingIds.contains(newId));
return newId;
}
4. Other Approaches
In other use cases, we can use other methods.
4.1. Random String by UUID
Java provides a standard method for generating unique identifiers using the package java.util.UUID:
String uniqueId = UUID.randomUUID().toString().replace("-", "");
These strings have hyphens. We remove them by replacing them with an empty string.
This way, we get a unique identifier with minimal collision probability. According to the IETF RFC 4122 standard, UUID-based identifiers have a 50% chance of a single collision after generating 2.71 quintillion (2.71 ×10¹⁸) UUIDs.
Furthermore, this method is thread-safe. However, the returned strings have 36 characters, including hyphens. This makes this method less useful for short IDs.
4.2. Timestamp-Based Identifiers
For systems that require unique sequential identifiers, we can use the current system time from the CPU clock of the underlying hardware. We can achieve thread safety via AtomicLong:
private static final AtomicLong currTime = new AtomicLong(System.currentTimeMillis());
public String generateTimestampId() {
return Long.toString(currTime.incrementAndGet(), Character.MAX_RADIX);
}
The following table captures the time taken to generate 1,000,000 identifiers on a quad-core MacBook Pro machine with 16 GB RAM:
| Method |
Average Time (ms) |
| Custom |
300 |
| Timestamp |
20 |
| UUID |
600 |
The timestamp-based method was the fastest in our experiment. The reason is that it uses the system clock with virtually no overhead. On the other hand, the UUID-based method was the slowest.
6. Conclusion
In this article, we explored various methods for generating random identifiers in Java.
While UUID is the safest default method, a custom generator is better suited for short identifiers with custom restrictions. For embedded and real-time systems where performance is the primary priority, timestamp-based atomic counters are the most effective.
As always, the complete code for this article is available over on GitHub. The post Generate Valid and Unique Identifiers first appeared on Baeldung.
Content mobilized by FeedBlitz RSS Services, the premium FeedBurner alternative. |