Java UUID

Java UUID: Ensuring Uniqueness in Your Applications

Java UUID mastery from the start! Learn to generate and implement Universally Unique Identifiers for enhanced code uniqueness and randomness in Java development.

What is UUID?

UUID stands for Universally Unique Identifier. It is a 128-bit value that can be used to identify any entity, such as objects, files, users, etc. A UUID is represented as a string of 32 hexadecimal digits, separated by four hyphens, such as:

e58ed763-928c-4155-bee9-fdbaaadc15f3

UUIDs are widely used in computing to uniquely identify entities such as objects, resources, or even entire systems.

Why Use UUIDs?

The primary advantage of UUIDs is their uniqueness. When you generate a UUID, you can be reasonably sure that it is unique globally, even when generated by different systems independently. This makes UUIDs ideal for scenarios where uniqueness is crucial, such as in distributed systems, databases, and network protocols.



UUID Structure

A UUID is typically represented as a string of 32 hexadecimal digits, grouped into five segments separated by hyphens. For example:

e58ed763-928c-4155-bee9-fdbaaadc15f3

Each segment represents a different part of the UUID, including the version and the uniqueness of the identifier.

#1. time_low: This part is the first 32 bits of the UUID, which stores the low field of the timestamp. The timestamp is the number of 100-nanosecond intervals since midnight, October 15, 1582. This part is used for version 1 UUIDs, which are based on the current time and the MAC address of the machine.

For example, in the UUID e58ed763-928c-4155-bee9-fdbaaadc15f3, the time_low part is e58ed763, which is equivalent to the 32 bits 11100101100011101101011101100011.

#2 time_mid: This part is the next 16 bits of the UUID, which stores the middle field of the timestamp. This part is also used for version 1 UUIDs, which are based on the current time and the MAC address of the machine.

For example, in the UUID e58ed763-928c-4155-bee9-fdbaaadc15f3, the time_mid part is 928c, which is equivalent to the 16 bits 1001001010001100.

#3 time_high_and_version: This part is the next 16 bits of the UUID, which stores the high field of the timestamp and the version of the UUID. The version is the first 4 bits of this part, which indicate the algorithm or the source of the UUID. 

For example, in the UUID e58ed763-928c-4155-bee9-fdbaaadc15f3, the time_high_and_version part is 4155, which is equivalent to the 16 bits 0100000101010101. The first 4 bits are 0100, which means that the version is 4, which means that the UUID is a random UUID. The next 12 bits are 000101010101, which are the high field of the timestamp for version 1 UUIDs, but are meaningless for version 4 UUIDs.

#4 variant_and_sequence: This part is the next 16 bits of the UUID, which stores the variant and the clock sequence of the UUID. The variant is the first 2 to 4 bits of this part, which indicates the format or the layout of the UUID.

The clock sequence is the remaining bits of this part, which store a random or pseudo-random value that changes whenever the system clock is adjusted. The clock sequence is used to avoid duplicates in case the timestamp is not unique. The clock sequence is only meaningful for version 1 UUIDs, which are based on the current time and the MAC address of the machine. For other versions, the clock sequence is just a random or pseudo-random value.

For example, in the UUID e58ed763-928c-4155-bee9-fdbaaadc15f3, the variant_and_sequence part is bee9, which is equivalent to the 16 bits 1011111011101001. The first 2 bits are 10, which means that the variant is 2, which means that the UUID follows the standard format. The next 14 bits are 11111011101001, which are the clock sequence for version 1 UUIDs, but are meaningless for version 4 UUIDs.

#5 node: This part is the last 48 bits of the UUID, which store the node identifier of the UUID. The node identifier is the MAC address of the network interface card for version 1 UUIDs, which are based on the current time and the MAC address of the machine. For other versions, the node identifier is just a random or pseudo-random value.

For example, in the UUID e58ed763-928c-4155-bee9-fdbaaadc15f3, the node part is fdbaaadc15f3, which is equivalent to the 48 bits 11111101101010101010110011010001010111110011. This value is the MAC address of the network interface card for version 1 UUIDs, but is meaningless for version 4 UUIDs.



Special UUIDs

Special UUIDs are UUIDs that have a specific pattern or meaning that differs from the usual UUIDs. Some examples of special UUIDs are:

  1. Nil UUID:
    • A Nil UUID is a UUID where all bits are set to zero.
    • It is represented as “00000000-0000-0000-0000-000000000000”
    • Nil UUIDs are often used to represent a missing or unknown UUID.
  2. Max UUID:
    • Max UUID is a UUID where all bits are set to one.
    • It is represented as “FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF”
    • These are not commonly used but can be employed for specific purposes or as a placeholder.

These special UUIDs are valid UUIDs according to the RFC 4122 standard, but they should be used with caution as they may cause confusion or errors in some applications or systems.

How to generate UUID in Java?

The Java language provides a built-in class called java.util.UUID that can be used to generate and manipulate UUIDs. This class has two constructors and three static methods for creating UUIDs:

#1. UUID(long mostSigBits, long leastSigBits): This constructor creates a UUID from two long values that represent the most significant and the least significant 64 bits of the UUID.

// Create a UUID from two long values
long most = 0xe58ed763928c4155L;
long least = 0xbee9fdbaaadc15f3L;

UUID uuid = new UUID(most, least);
System.out.println(uuid); // e58ed763-928c-4155-bee9-fdbaaadc15f3
Java

#2. UUUID.fromString(String name): This static method creates a UUID from a string that matches the format of a UUID. This method is particularly useful when you have a UUID represented as a string, and you want to work with it as a UUID object in your Java code. For example:

// Create a UUID from a string
String name = "e58ed763-928c-4155-bee9-fdbaaadc15f3";

UUID uuid = UUID.fromString(name);
System.out.println(uuid); // e58ed763-928c-4155-bee9-fdbaaadc15f3
Java

If the input string passed to the fromString method is not a valid UUID representation, it will throw an IllegalArgumentException. The IllegalArgumentException is a runtime exception that signals that a method has been invoked with an illegal or inappropriate argument.

#3. UUID.randomUUID(): This static method generates a random UUID using a cryptographically strong pseudo-random number generator. This method creates a version 4 UUID, which is one of the five standard versions of UUIDs. For example:

// Generate a random UUID
UUID uuid = UUID.randomUUID();

System.out.println(uuid);// 80410f04-ddde-4539-8720-e0703bd94d3d
Java

#4. UUID.nameUUIDFromBytes(byte[] name): This static method generates a UUID from a byte array that represents a name or a namespace. This method creates a version 3 UUID, which is based on the MD5 hash of the input. For example:

// Generate a UUID from a byte array
byte[] bytes = "Hello World".getBytes();
UUID uuid = UUID.nameUUIDFromBytes(bytes);

System.out.println(uuid); // b10a8db1-64e0-3541-85b7-a99be72e3fe5
Java


What are the Different Versions of UUIDs?

There are five standard versions of UUIDs, each with a different algorithm and purpose. The version of a UUID is indicated by the thirteenth hexadecimal digit of the UUID, such as:

xxxxxxxx-xxxx-Vxxx-xxxx-xxxxxxxxxxxx

The possible values of V and their corresponding versions are:

Version 1: Time-based UUID

This version is based on the current time and the MAC address of the machine that generates the UUID. This version ensures uniqueness across space and time, but it also exposes the MAC address and the creation time of the UUID, which may pose a security risk.

Version 2: DCE Security UUID

This version is similar to version 1, but it also includes a local domain and a local identifier, such as a user ID or a group ID. This version is used for identifying users or groups in a distributed system.

Version 3: Name-based UUID Using MD5

This version is based on the MD5 hash of a name or a namespace, such as a URL, a domain name, an email address, etc. This version ensures that the same name or namespace will always generate the same UUID, but it also means that different names or namespaces may generate the same UUID, which may cause collisions.

Version 4: Randomly Generated UUID

This version is based on a random or pseudo-random number generator. This version ensures high randomness and low probability of collisions, but it also means that the same name or namespace may generate different UUIDs, which may cause inconsistency.

Version 5: Name-based UUID Using SHA-1

This version is similar to version 3, but it uses the SHA-1 hash instead of the MD5 hash. This version provides better security and uniqueness than version 3, but it also has the same drawbacks.

When to Use Which Version?

The choice of which version of UUID to use depends on the requirements and the trade-offs of the application. Here are some general guidelines:

  • If you need a UUID that is unique and random, use version 4.
  • If you need a UUID that is persistent and consistent for a given name or namespace, use version 3 or 5.
  • If you need a UUID that is based on the current time and the MAC address, use version 1.
  • If you need a UUID that is based on the user ID or the group ID, use version 2.

However, you should also consider the following factors:

  • The security and privacy of the UUID, as some versions may expose sensitive data, such as the MAC address, the user ID, the group ID, or the creation time of the UUID. You should avoid using these versions if you want to protect the identity and the context of the user or the group.
  • The performance and the scalability of the UUID, as some versions may require more computation, communication, or synchronization than others. For example, version 1 may require accessing the system clock and the network interface card, version 2 may require accessing the local domain and the local identifier, versions 3 and 5 may require hashing the name or the namespace, and version 4 may require generating random numbers. You should choose the version that best suits the resources and the constraints of your application.
  • The compatibility and interoperability of the UUID, as some versions may not be supported or recognized by other systems or libraries. For example, version 2 is specific to the DCE system, and version 5 is not widely implemented. You should check the availability and compatibility of the version that you want to use with the systems or the libraries that you are working with.


What is the Variant Method in Java UUID?

The variant method of the UUID class returns the variant number of the UUID, which indicates the layout or the format of the UUID. The variant number is determined by the seventeenth hexadecimal digit of the UUID, such as:

xxxxxxxx-xxxx-xxxx-Axxx-xxxxxxxxxxxx

The possible values of A and their corresponding variants are:

  • 0xx: This format is reserved for NCS compatibility, which means that it follows the rules of the Network Computing System, an old distributed system that used UUIDs before the RFC 4122 standard was established. This format is rarely used nowadays.
  • 10x: This format is the standard format used by the UUID class in Java and most other systems and libraries that follow the RFC 4122 standard. This format uses the fourth hexadecimal digit to indicate the version of the UUID, which is one of the five standard versions based on different algorithms. This format is the most common and recommended one.
  • 110: This format is reserved for Microsoft compatibility, which means that it follows the rules of the Microsoft GUID, a variant of UUID that is used by some Microsoft products and services. This format is similar to the standard format, but it uses a different variant number and a different byte order.
  • 111: This format is reserved for future use, which means that it may be defined or used by some new systems or standards in the future. This format is not used currently.

The variant number affects how the rest of the bits in the UUID are interpreted. To get the variant number of a UUID object in Java, you can use the variant() method, which returns an int value. For example:

// Generate a random UUID
UUID uuid = UUID.randomUUID();
System.out.println(uuid); // a082f2b5-3bb9-40b0-9ab8-78e56562b140

// Get the variant number of the UUID
int variant = uuid.variant();
System.out.println(variant); // 2
Java

The variant() method returns 2, which means that the UUID follows the standard format. If the variant() method returns 0, 6, or 7, it means that the UUID follows the other formats.

Why value 2 is printed in the output?

In binary, the seventeenth hex digit “9” is represented as “1001.” The most significant bits are the first two bits, which are “10.” The “10” pattern indicates the RFC 4122/DCE variant, and in decimal, “10” is equivalent to 2. Therefore, the variant method returns 2 for this UUID.



Key Methods of Java UUID Class

The UUID class provides various methods to create, parse, and manipulate UUID objects. Here are some of the methods:

1. getLeastSignificantBits(): This method returns the least significant 64 bits of the UUID as a long value. For example:

// Create a UUID from a string
UUID uuid = UUID.fromString("e58ed763-928c-4155-bee9-fdbaaadc15f3");
System.out.println(uuid); // e58ed763-928c-4155-bee9-fdbaaadc15f3

// Get the least significant 64 bits of the UUID
long least = uuid.getLeastSignificantBits();
System.out.println(least); // -4689938558757366285
Java

2. getMostSignificantBits(): This method returns the most significant 64 bits of the UUID as a long value. For example:

// Create a UUID from a string
UUID uuid = UUID.fromString("e58ed763-928c-4155-bee9-fdbaaadc15f3");
System.out.println(uuid); // e58ed763-928c-4155-bee9-fdbaaadc15f3

// Get the most significant 64 bits of the UUID
long most = uuid.getMostSignificantBits();
System.out.println(most); // -1905348769670741675
Java

3. timestamp(): This method returns the timestamp value associated with the UUID, which is the number of 100-nanosecond intervals since midnight, October 15, 1582. This method is only valid for version 1 UUIDs, which are based on the current time and the MAC address of the machine. For other versions, this method throws an UnsupportedOperationException. For example:

// Generate a version 1 UUID
UUID uuid = UUID.fromString("550e8400-e29b-11d4-a716-446655440000");
System.out.println(uuid); // 550e8400-e29b-11d4-a716-446655440000

// Get the timestamp value of the UUID
long timestamp = uuid.timestamp();
System.out.println(timestamp); // 131979445875409920
Java

4. clockSequence(): This method returns the clock sequence value associated with the UUID, which is a random or pseudo-random value that changes whenever the system clock is adjusted. This method is only valid for version 1 UUIDs, which are based on the current time and the MAC address of the machine. For other versions, this method throws an UnsupportedOperationException. For example:

// Generate a version 1 UUID
UUID uuid = UUID.fromString("550e8400-e29b-11d4-a716-446655440000");
System.out.println(uuid); // 550e8400-e29b-11d4-a716-446655440000

// Get the clock sequence value of the UUID
int clockSequence = uuid.clockSequence();
System.out.println(clockSequence); // 10006
Java

5. node(): This method returns the node value associated with the UUID, which is the MAC address of the network interface card. This method is only valid for version 1 UUIDs, which are based on the current time and the MAC address of the machine. For other versions, this method throws an UnsupportedOperationException. For example:

// Generate a version 1 UUID
UUID uuid = UUID.fromString("550e8400-e29b-11d4-a716-446655440000");
System.out.println(uuid); // 550e8400-e29b-11d4-a716-446655440000

// Get the node value of the UUID
long node = uuid.node();
System.out.println(node); // 75206307872768
Java

6. equals(Object obj): This method compares this UUID with the specified object for equality. The method returns true if and only if the specified object is also a UUID object and has the same value as this UUID. For example:

// Create two UUID objects
UUID uuid1 = UUID.fromString("e58ed763-928c-4155-bee9-fdbaaadc15f3");
UUID uuid2 = UUID.fromString("e58ed763-928c-4155-bee9-fdbaaadc15f3");

// Compare the UUID objects for equality
boolean equals = uuid1.equals(uuid2);
System.out.println(equals); // true
Java

7. compareTo(UUID val): This method compares this UUID with the specified UUID for order. The method returns a negative integer, zero, or a positive integer as this UUID is less than, equal to, or greater than the specified UUID. The comparison is based on the value of the UUID as a 128-bit value. For example:

// Create two UUID objects
UUID uuid1 = UUID.fromString("e58ed763-928c-4155-bee9-fdbaaadc15f3");
UUID uuid2 = UUID.fromString("9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d");

// Compare the UUID objects for order
int comparison = uuid1.compareTo(uuid2);
System.out.println(comparison); // 1
Java

8. toString(): This method returns a string representation of the UUID, which consists of 32 hexadecimal digits, separated by four hyphens, as described in the RFC 4122 standard. For example:

// Generate a random UUID
UUID uuid = UUID.randomUUID();
System.out.println(uuid); // 9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d

// Get the string representation of the UUID
String string = uuid.toString();
System.out.println(string); // 9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d
Java


Limitations of UUID

While UUIDs are widely used, it’s important to acknowledge their limitations for optimal usage. Let’s understand the challenges associated with UUIDs.

  • Storage: A UUID takes up 16 bytes of memory, which is four times larger than an integer-type ID value. This means that UUIDs require more disk space and network bandwidth than integer IDs.
  • Performance: Generating UUIDs is generally slower than generating incremental integer-type IDs, especially for type 1 UUIDs, which are based on the current time and the MAC address of the machine.
  • Indexing: Using UUIDs as primary keys can cause fragmentation and decrease the efficiency of clustered indexes because UUIDs are inserted in random positions, not at the end of the table. This can affect the query speed and the insert performance of the database.
  • Readability: UUIDs are hard to read, write, and debug because they are long and complex strings of hexadecimal digits. They are also not user-friendly, as they cannot be easily remembered or communicated.
  • Ordering: UUIDs cannot be used to sort or order data by the insertion time, because they are not sequential. This can make it difficult to track the history or the chronology of the data.

Things to Consider

When working with Java UUIDs, there are several important considerations to keep in mind. Here’s a list of key factors to consider:

  • Guaranteeing Uniqueness: Ensure generated UUIDs are universally unique, considering the extremely low probability of collisions.
  • Navigating UUID Versions: Choose the appropriate UUID version (e.g., time-based, name-based, random) based on your application’s specific needs.
  • Balancing Performance: Consider the performance implications, especially when generating a large number of UUIDs, and balance with high randomness.
  • Safeguarding Security: Be cautious about using time-based UUIDs (version 1) due to potential information exposure; prefer version 4 for enhanced security.


FAQs

What is the primary difference between UUID and GUID?

How to generate a random UUID in Java?

How to get the variant and the version of a UUID in Java?

In which scenarios UUID should be used?

Conclusion

In a nutshell, Java UUIDs provide a reliable way to generate unique identifiers in Java programming. With different versions and methods, they offer versatility for various applications. While they’re handy for most scenarios, it’s important to be mindful of their limitations, especially in security-sensitive situations. Overall, Java UUIDs are a valuable tool for ensuring uniqueness in your code.

Learn More

#

Interested in learning more?

Discover the power of virtual threads in Java!

Top Picks for Learning Java

Explore the recommended Java books tailored for learners at different levels, from beginners to advanced programmers.

Disclaimer: The products featured or recommended on this site are affiliated. If you purchase these products through the provided links, I may earn a commission at no additional cost to you.

1
Java: The Complete Reference
13th Edition

Java: The Complete Reference

  • All Levels Covered: Designed for novice, intermediate, and professional programmers alike
  • Accessible Source Code: Source code for all examples and projects are available for download
  • Clear Writing Style: Written in the clear, uncompromising style Herb Schildt is famous for
2
Head First Java: A Brain-Friendly Guide

Head First Java: A Brain-Friendly Guide

  • Engaging Learning: It uses a fun approach to teach Java and object-oriented programming.
  • Comprehensive Content: Covers Java's basics and advanced topics like lambdas and GUIs.
  • Interactive Learning: The book's visuals and engaging style make learning Java more enjoyable.
3
Modern Java in Action: Lambdas, streams, functional and reactive programming
2nd Edition

Modern Java in Action: Lambdas, streams, functional and reactive programming

  • Latest Java Features: Explores modern Java functionalities from version 8 and beyond, like streams, modules, and concurrency.
  • Real-world Applications: Demonstrates how to use these new features practically, enhancing understanding and coding skills.
  • Developer-Friendly: Tailored for Java developers already familiar with core Java, making it accessible for advancing their expertise.
4
Java For Dummies
8th Edition

Java For Dummies

  • Java Essentials: Learn fundamental Java programming through easy tutorials and practical tips in the latest edition of the For Dummies series.
  • Programming Basics: Gain control over program flow, master classes, objects, and methods, and explore functional programming features.
  • Updated Coverage: Covers Java 17, the latest long-term support release, including the new 'switch' statement syntax, making it perfect for beginners or those wanting to brush up their skills.

Add a Comment

Your email address will not be published.