Generate UUID in Java: Complete Developer Guide

Introduction to UUID in Java

Java provides native support for UUID (Universally Unique Identifier) through the java.util.UUID class. This comprehensive guide will show you how to generate, validate, and work with UUIDs in your Java applications, from basic cases to advanced implementations.

UUIDs are 128-bit identifiers that are globally unique, making them perfect for distributed systems, database primary keys, and any scenario requiring unique identifiers without central coordination.

UUID Generation Methods in Java

Basic UUID Generation

The simplest way to generate a random UUID (Version 4) in Java using UUID.randomUUID(). This method is thread-safe and generates cryptographically strong UUIDs.

import java.util.UUID;

public class UUIDGenerator {
    public static void main(String[] args) {
        // Generate a random UUID (Version 4)
        UUID uuid = UUID.randomUUID();
        System.out.println("Generated UUID: " + uuid.toString());
        
        // Convert to string without hyphens
        String uuidWithoutHyphens = uuid.toString().replace("-", "");
        System.out.println("UUID without hyphens: " + uuidWithoutHyphens);
    }
}

UUID.randomUUID() generates a Version 4 UUID using a cryptographically strong random number generator. The resulting UUID is guaranteed to be unique with extremely high probability.

Bulk UUID Generation

Generate multiple UUIDs efficiently for batch processing, data imports, or database initialization. Ideal when you need to create many unique identifiers at once.

import java.util.UUID;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class BulkUUIDGenerator {
    // Traditional approach
    public static List<UUID> generateMultipleUUIDs(int count) {
        List<UUID> uuids = new ArrayList<>();
        for (int i = 0; i < count; i++) {
            uuids.add(UUID.randomUUID());
        }
        return uuids;
    }
    
    // Stream-based approach
    public static List<UUID> generateUUIDsStream(int count) {
        return Stream.generate(UUID::randomUUID)
                     .limit(count)
                     .collect(Collectors.toList());
    }
    
    public static void main(String[] args) {
        // Generate 10 UUIDs
        List<UUID> uuidList = generateUUIDsStream(10);
        
        // Print all generated UUIDs
        uuidList.forEach(uuid -> System.out.println(uuid.toString()));
    }
}

This example shows both traditional and modern Java 8+ approaches to bulk UUID generation. The stream-based approach is more concise and functional, while the traditional approach offers more control over the generation process.

Name-Based UUID Generation

Create deterministic UUIDs based on names (Version 3), convert between strings and UUIDs, and access metadata like version and variant.

import java.util.UUID;
import java.nio.charset.StandardCharsets;

public class NameBasedUUID {
    public static void main(String[] args) {
        // Create a name-based UUID (Version 3 - MD5)
        String namespace = "6ba7b810-9dad-11d1-80b4-00c04fd430c8";
        String name = "example.com";
        UUID uuid3 = UUID.nameUUIDFromBytes(
            (namespace + name).getBytes(StandardCharsets.UTF_8)
        );
        System.out.println("UUID v3: " + uuid3);
        
        // Create from string
        String uuidString = "550e8400-e29b-41d4-a716-446655440000";
        try {
            UUID fromString = UUID.fromString(uuidString);
            System.out.println("UUID from string: " + fromString);
            
            // Get UUID metadata
            System.out.println("Version: " + fromString.version());
            System.out.println("Variant: " + fromString.variant());
            
            // Compare UUIDs
            UUID another = UUID.randomUUID();
            System.out.println("Comparison result: " + fromString.compareTo(another));
        } catch (IllegalArgumentException e) {
            System.err.println("Invalid UUID format: " + e.getMessage());
        }
    }
}

Name-based UUIDs are deterministic, meaning the same input will always produce the same UUID. This is useful for creating consistent identifiers based on existing data.

Custom UUID Generation

Implement custom UUID generators for specific use cases, including time-based UUIDs and sequential UUIDs optimized for database performance.

import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
import java.nio.ByteBuffer;
import java.util.concurrent.atomic.AtomicLong;

public class CustomUUIDGenerator {
    // Generate time-based UUID (similar to Version 1)
    public static UUID generateTimeBasedUUID() {
        long mostSigBits = System.currentTimeMillis() << 32;
        mostSigBits |= ThreadLocalRandom.current().nextInt() & 0xFFFFFFFFL;
        
        long leastSigBits = ThreadLocalRandom.current().nextLong();
        
        // Set version (1) and variant bits
        mostSigBits &= ~0xF000L;
        mostSigBits |= 0x1000L;  // Version 1
        
        leastSigBits &= ~0xC000000000000000L;
        leastSigBits |= 0x8000000000000000L;  // Variant 10
        
        return new UUID(mostSigBits, leastSigBits);
    }
    
    // Sequential UUID generator for database optimization
    public static class SequentialUUIDGenerator {
        private final AtomicLong counter = new AtomicLong(0);
        private final long timestamp = System.currentTimeMillis();
        
        public UUID next() {
            ByteBuffer buffer = ByteBuffer.allocate(16);
            buffer.putLong(timestamp);
            buffer.putLong(counter.incrementAndGet());
            
            buffer.rewind();
            long mostSigBits = buffer.getLong();
            long leastSigBits = buffer.getLong();
            
            return new UUID(mostSigBits, leastSigBits);
        }
    }
    
    public static void main(String[] args) {
        // Generate custom time-based UUID
        UUID timeBased = generateTimeBasedUUID();
        System.out.println("Time-based UUID: " + timeBased);
        
        // Generate sequential UUIDs
        SequentialUUIDGenerator seqGen = new SequentialUUIDGenerator();
        for (int i = 0; i < 5; i++) {
            System.out.println("Sequential UUID " + i + ": " + seqGen.next());
        }
    }
}

Custom UUID generators can be optimized for specific use cases. Sequential UUIDs improve database index performance, while time-based UUIDs can include timestamp information for sorting and analysis.

UUID Utility Functions

Here's a comprehensive utility class for common UUID operations in Java applications:

import java.util.UUID;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class UUIDUtils {
    // Save UUIDs to text file
    public static void saveUUIDsToFile(String filename, int count) {
        try (PrintWriter writer = new PrintWriter(new FileWriter(filename))) {
            for (int i = 0; i < count; i++) {
                writer.println(UUID.randomUUID().toString());
            }
            System.out.println("Saved " + count + " UUIDs to " + filename);
        } catch (IOException e) {
            System.err.println("Error writing to file: " + e.getMessage());
        }
    }
    
    // Save as CSV with metadata
    public static void saveAsCSV(String filename, int count) {
        try (PrintWriter writer = new PrintWriter(new FileWriter(filename))) {
            writer.println("Index,UUID,Timestamp,Version");
            for (int i = 0; i < count; i++) {
                UUID uuid = UUID.randomUUID();
                writer.printf("%d,%s,%d,%d%n", 
                    i + 1, 
                    uuid.toString(), 
                    System.currentTimeMillis(),
                    uuid.version());
            }
            System.out.println("Saved " + count + " UUIDs to CSV");
        } catch (IOException e) {
            System.err.println("Error writing to CSV: " + e.getMessage());
        }
    }
    
    // Read UUIDs from file
    public static List<UUID> readUUIDsFromFile(String filename) {
        try {
            return Files.lines(Paths.get(filename))
                       .map(String::trim)
                       .filter(line -> !line.isEmpty())
                       .map(UUID::fromString)
                       .collect(Collectors.toList());
        } catch (IOException e) {
            System.err.println("Error reading file: " + e.getMessage());
            return List.of();
        }
    }
    
    // Convert UUID to different formats
    public static String toBase64(UUID uuid) {
        ByteBuffer bb = ByteBuffer.wrap(new byte[16]);
        bb.putLong(uuid.getMostSignificantBits());
        bb.putLong(uuid.getLeastSignificantBits());
        return java.util.Base64.getEncoder()
                               .encodeToString(bb.array())
                               .replace("=", "");
    }
}

This utility class provides essential functions for working with UUIDs, including file I/O operations, format conversions, and batch processing capabilities.

UUID Validation

Validate UUID strings using regular expressions and Java's native parser. Essential for validating user input and ensuring data integrity.

import java.util.UUID;
import java.util.regex.Pattern;

public class UUIDValidator {
    // Regex pattern for UUID validation
    private static final Pattern UUID_PATTERN = Pattern.compile(
        "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"
    );
    
    // Regex pattern for UUID without hyphens
    private static final Pattern UUID_NO_HYPHENS = Pattern.compile(
        "^[0-9a-fA-F]{32}$"
    );
    
    // Validate using regex
    public static boolean isValidUUID(String uuid) {
        if (uuid == null) return false;
        return UUID_PATTERN.matcher(uuid).matches();
    }
    
    // Validate using UUID parser
    public static boolean tryParseUUID(String uuid) {
        try {
            UUID.fromString(uuid);
            return true;
        } catch (IllegalArgumentException e) {
            return false;
        }
    }
    
    // Normalize UUID format
    public static String normalizeUUID(String input) {
        if (input == null) return null;
        
        // Remove all non-hex characters
        String cleaned = input.replaceAll("[^0-9a-fA-F]", "");
        
        // Check if we have exactly 32 hex characters
        if (cleaned.length() != 32) {
            throw new IllegalArgumentException("Invalid UUID length");
        }
        
        // Insert hyphens at the correct positions
        return String.format("%s-%s-%s-%s-%s",
            cleaned.substring(0, 8),
            cleaned.substring(8, 12),
            cleaned.substring(12, 16),
            cleaned.substring(16, 20),
            cleaned.substring(20, 32)
        );
    }
    
    public static void main(String[] args) {
        String[] testUUIDs = {
            "550e8400-e29b-41d4-a716-446655440000",  // Valid
            "550e8400e29b41d4a716446655440000",      // Valid (no hyphens)
            "not-a-uuid",                            // Invalid
            "550e8400-e29b-41d4-a716",              // Invalid (too short)
            UUID.randomUUID().toString()             // Valid
        };
        
        for (String test : testUUIDs) {
            System.out.println("\nTesting: " + test);
            System.out.println("Regex validation: " + isValidUUID(test));
            System.out.println("Parser validation: " + tryParseUUID(test));
            
            try {
                String normalized = normalizeUUID(test);
                System.out.println("Normalized: " + normalized);
            } catch (Exception e) {
                System.out.println("Normalization failed: " + e.getMessage());
            }
        }
    }
}

UUID validation is crucial for data integrity. This example shows multiple validation approaches and includes normalization functionality to handle different UUID formats.

Performance Considerations

When generating UUIDs at scale, performance becomes important. Here's how to optimize UUID generation for high-throughput scenarios:

import java.util.UUID;
import java.util.concurrent.*;
import java.security.SecureRandom;
import java.util.Random;
import java.util.concurrent.atomic.AtomicLong;

public class UUIDPerformance {
    // Thread-local Random for better performance in multi-threaded environments
    private static final ThreadLocal<Random> threadLocalRandom = 
        ThreadLocal.withInitial(() -> new Random());
    
    // Benchmark different UUID generation approaches
    public static void benchmarkUUIDGeneration(int iterations) {
        // Standard UUID.randomUUID()
        long start = System.nanoTime();
        for (int i = 0; i < iterations; i++) {
            UUID.randomUUID();
        }
        long standardTime = System.nanoTime() - start;
        
        // Custom UUID with ThreadLocalRandom
        start = System.nanoTime();
        for (int i = 0; i < iterations; i++) {
            generateFastUUID();
        }
        long customTime = System.nanoTime() - start;
        
        System.out.printf("Standard UUID: %d ms%n", standardTime / 1_000_000);
        System.out.printf("Custom UUID: %d ms%n", customTime / 1_000_000);
        System.out.printf("Performance improvement: %.2fx%n", 
            (double) standardTime / customTime);
    }
    
    // Faster UUID generation for non-cryptographic use cases
    public static UUID generateFastUUID() {
        Random random = threadLocalRandom.get();
        long mostSigBits = random.nextLong();
        long leastSigBits = random.nextLong();
        
        // Set version and variant bits
        mostSigBits &= 0xFFFFFFFFFFFF0FFFL; // Clear version
        mostSigBits |= 0x0000000000004000L; // Set version to 4
        
        leastSigBits &= 0x3FFFFFFFFFFFFFFFL; // Clear variant
        leastSigBits |= 0x8000000000000000L; // Set variant
        
        return new UUID(mostSigBits, leastSigBits);
    }
    
    // Parallel UUID generation
    public static CompletableFuture<List<UUID>> generateParallel(int count) {
        return CompletableFuture.supplyAsync(() -> {
            return IntStream.range(0, count)
                           .parallel()
                           .mapToObj(i -> UUID.randomUUID())
                           .collect(Collectors.toList());
        });
    }
    
    public static void main(String[] args) throws Exception {
        System.out.println("UUID Generation Performance Test\n");
        
        // Warm up
        for (int i = 0; i < 10000; i++) {
            UUID.randomUUID();
            generateFastUUID();
        }
        
        // Benchmark
        benchmarkUUIDGeneration(1_000_000);
        
        // Test parallel generation
        System.out.println("\nParallel Generation Test:");
        long start = System.nanoTime();
        CompletableFuture<List<UUID>> future = generateParallel(100_000);
        List<UUID> uuids = future.get();
        long elapsed = System.nanoTime() - start;
        System.out.printf("Generated %d UUIDs in %d ms%n", 
            uuids.size(), elapsed / 1_000_000);
    }
}

For high-performance applications, consider using ThreadLocalRandom instead of SecureRandom when cryptographic strength isn't required. Parallel generation can significantly improve throughput for bulk operations.

Conclusion

Java provides excellent built-in support for UUID generation and manipulation. Whether you need simple random identifiers or complex custom implementations, the UUID class offers a solid foundation. Remember to choose the appropriate method based on your specific requirements for uniqueness, performance, and ordering.

For production applications, consider factors such as database storage optimization, validation requirements, and performance implications. The examples in this guide provide a comprehensive toolkit for working with UUIDs in Java applications.

Need to generate UUIDs quickly? Try our online UUID generator for instant UUID creation without any coding required.

© UUIDGenerator.co v1.0 All rights reserved (2025)