Generating 8-character only UUIDs

JavaUuid

Java Problem Overview


UUID libraries generate 32-character UUIDs.

I want to generate 8-character only UUIDs, is it possible?

Java Solutions


Solution 1 - Java

It is not possible since a UUID is a 16-byte number per definition. But of course, you can generate 8-character long unique strings (see the other answers).

Also be careful with generating longer UUIDs and substring-ing them, since some parts of the ID may contain fixed bytes (e.g. this is the case with MAC, DCE and MD5 UUIDs).

Solution 2 - Java

You can try RandomStringUtils class from apache.commons:

import org.apache.commons.lang3.RandomStringUtils;

final int SHORT_ID_LENGTH = 8;

// all possible unicode characters
String shortId = RandomStringUtils.random(SHORT_ID_LENGTH);

Please keep in mind, that it will contain all possible characters which is neither URL nor human friendly.

So check out other methods too:

// HEX: 0-9, a-f. For example: 6587fddb, c0f182c1
shortId = RandomStringUtils.random(8, "0123456789abcdef"); 

// a-z, A-Z. For example: eRkgbzeF, MFcWSksx
shortId = RandomStringUtils.randomAlphabetic(8); 

// 0-9. For example: 76091014, 03771122
shortId = RandomStringUtils.randomNumeric(8); 

// a-z, A-Z, 0-9. For example: WRMcpIk7, s57JwCVA
shortId = RandomStringUtils.randomAlphanumeric(8); 

As others said probability of id collision with smaller id can be significant. Check out how birthday problem applies to your case. You can find nice explanation how to calculate approximation in this answer.

Solution 3 - Java

First: Even the unique IDs generated by java UUID.randomUUID or .net GUID are not 100% unique. Especialy UUID.randomUUID is "only" a 128 bit (secure) random value. So if you reduce it to 64 bit, 32 bit, 16 bit (or even 1 bit) then it becomes simply less unique.

So it is at least a risk based decisions, how long your uuid must be.

Second: I assume that when you talk about "only 8 characters" you mean a String of 8 normal printable characters.

If you want a unique string with length 8 printable characters you could use a base64 encoding. This means 6bit per char, so you get 48bit in total (possible not very unique - but maybe it is ok for you application)

So the way is simple: create a 6 byte random array

 SecureRandom rand;
 // ...
 byte[] randomBytes = new byte[16];
 rand.nextBytes(randomBytes);

And then transform it to a Base64 String, for example by org.apache.commons.codec.binary.Base64

BTW: it depends on your application if there is a better way to create "uuid" then by random. (If you create a the UUIDs only once per second, then it is a good idea to add a time stamp) (By the way: if you combine (xor) two random values, the result is always at least as random as the most random of the both).

Solution 4 - Java

As @Cephalopod stated it isn't possible but you can shorten a UUID to 22 characters

public static String encodeUUIDBase64(UUID uuid) {
        ByteBuffer bb = ByteBuffer.wrap(new byte[16]);
        bb.putLong(uuid.getMostSignificantBits());
        bb.putLong(uuid.getLeastSignificantBits());
        return StringUtils.trimTrailingCharacter(BaseEncoding.base64Url().encode(bb.array()), '=');
}

Solution 5 - Java

How about this one? Actually, this code returns 13 characters max, but it shorter than UUID.

import java.nio.ByteBuffer;
import java.util.UUID;
 
/**
 * Generate short UUID (13 characters)
 * 
 * @return short UUID
 */
public static String shortUUID() {
  UUID uuid = UUID.randomUUID();
  long l = ByteBuffer.wrap(uuid.toString().getBytes()).getLong();
  return Long.toString(l, Character.MAX_RADIX);
}

Solution 6 - Java

Not a UUID, but this works for me:

UUID.randomUUID().toString().replace("-","").substring(0,8)

Solution 7 - Java

This is a similar way I'm using here to generate an unique error code, based on Anton Purin answer, but relying on the more appropriate org.apache.commons.text.RandomStringGenerator instead of the (once, not anymore) deprecated org.apache.commons.lang3.RandomStringUtils:

@Singleton
@Component
public class ErrorCodeGenerator implements Supplier<String> {
	
	private RandomStringGenerator errorCodeGenerator;

	public ErrorCodeGenerator() {
		errorCodeGenerator = new RandomStringGenerator.Builder()
				.withinRange('0', 'z')
				.filteredBy(t -> t >= '0' && t <= '9', t -> t >= 'A' && t <= 'Z', t -> t >= 'a' && t <= 'z')
				.build();
	}

	@Override
	public String get() {
		return errorCodeGenerator.generate(8);
	}

}

All advices about collision still apply, please be aware of them.

Solution 8 - Java

Actually I want timestamp based shorter unique identifier, hence tried the below program.

It is guessable with nanosecond + ( endians.length * endians.length ) combinations.

public class TimStampShorterUUID {
	
	private static final Character [] endians = 
		   {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 
			'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 
			'u', 'v', 'w', 'x', 'y', 'z', 
			'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 
			'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 
			'U', 'V', 'W', 'X', 'Y', 'Z',
			'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
			};
	
   private static ThreadLocal<Character> threadLocal =  new ThreadLocal<Character>();
   
   private static AtomicLong iterator = new AtomicLong(-1);
   
	 
	public static String generateShorterTxnId() {
		// Keep this as secure random when we want more secure, in distributed systems
		int firstLetter = ThreadLocalRandom.current().nextInt(0, (endians.length));
		
		//Sometimes your randomness and timestamp will be same value,
        //when multiple threads are trying at the same nano second
        //time hence to differentiate it, utilize the threads requesting
		//for this value, the possible unique thread numbers == endians.length
		Character secondLetter = threadLocal.get();
		if (secondLetter == null) {
			synchronized (threadLocal) {
				if (secondLetter == null) {
					threadLocal.set(endians[(int) (iterator.incrementAndGet() % endians.length)]);
				}
			}
			secondLetter = threadLocal.get();
		}
		return "" + endians[firstLetter] + secondLetter + System.nanoTime();
	}
	
	
	public static void main(String[] args) {
		
		Map<String, String> uniqueKeysTestMap = new ConcurrentHashMap<>();
		
		Thread t1 = new Thread() {	
			@Override
			public void run() {
				while(true) {
					String time = generateShorterTxnId();
					String result = uniqueKeysTestMap.put(time, "");
					if(result != null) {
						System.out.println("failed! - " + time);
					}
				}
			}		
		};
		
		Thread t2 = new Thread() {	
			@Override
			public void run() {
				while(true) {
					String time = generateShorterTxnId();
					String result = uniqueKeysTestMap.put(time, "");
					if(result != null) {
						System.out.println("failed! - " + time);
					}
				}
			}		
		};

		Thread t3 = new Thread() {	
			@Override
			public void run() {
				while(true) {
					String time = generateShorterTxnId();
					String result = uniqueKeysTestMap.put(time, "");
					if(result != null) {
						System.out.println("failed! - " + time);
					}
				}
			}		
		};
		
		Thread t4 = new Thread() {	
			@Override
			public void run() {
				while(true) {
					String time = generateShorterTxnId();
					String result = uniqueKeysTestMap.put(time, "");
					if(result != null) {
						System.out.println("failed! - " + time);
					}
				}
			}		
		};
		
		Thread t5 = new Thread() {	
			@Override
			public void run() {
				while(true) {
					String time = generateShorterTxnId();
					String result = uniqueKeysTestMap.put(time, "");
					if(result != null) {
						System.out.println("failed! - " + time);
					}
				}
			}
		};
		
		Thread t6 = new Thread() {	
			@Override
			public void run() {
				while(true) {
					String time = generateShorterTxnId();
					String result = uniqueKeysTestMap.put(time, "");
					if(result != null) {
						System.out.println("failed! - " + time);
					}
				}
			}	
		};

		Thread t7 = new Thread() {	
			@Override
			public void run() {
				while(true) {
					String time = generateShorterTxnId();
					String result = uniqueKeysTestMap.put(time, "");
					if(result != null) {
						System.out.println("failed! - " + time);
					}
				}
			}
		};
		
		t1.start();
		t2.start();
		t3.start();
		t4.start();
		t5.start();
		t6.start();
		t7.start();
	}
}

UPDATE: This code will work on single JVM, but we should think on distributed JVM, hence i am thinking two solutions one with DB and another one without DB.

with DB

Company name (shortname 3 chars) ---- Random_Number ---- Key specific redis COUNTER
(3 char) ------------------------------------------------ (2 char) ---------------- (11 char)

without DB

IPADDRESS ---- THREAD_NUMBER ---- INCR_NUMBER ---- epoch milliseconds
(5 chars) ----------------- (2char) ----------------------- (2 char) ----------------- (6 char)

will update you once coding is done.

Solution 9 - Java

I do not think that it is possible but you have a good workaround.

  1. cut the end of your UUID using substring()

  2. use code new Random(System.currentTimeMillis()).nextInt(99999999); this will generate random ID up to 8 characters long.

  3. generate alphanumeric id:

     char[] chars = "abcdefghijklmnopqrstuvwxyzABSDEFGHIJKLMNOPQRSTUVWXYZ1234567890".toCharArray();
     Random r = new Random(System.currentTimeMillis());
     char[] id = new char[8];
     for (int i = 0;  i < 8;  i++) {
     	id[i] = chars[r.nextInt(chars.length)];
     }
     return new String(id);
    

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionM.J.View Question on Stackoverflow
Solution 1 - JavaCephalopodView Answer on Stackoverflow
Solution 2 - JavaAntonView Answer on Stackoverflow
Solution 3 - JavaRalphView Answer on Stackoverflow
Solution 4 - Javabstick12View Answer on Stackoverflow
Solution 5 - Javasanghoon2View Answer on Stackoverflow
Solution 6 - JavaSimon Ernesto Cardenas ZarateView Answer on Stackoverflow
Solution 7 - JavaBrunoJCMView Answer on Stackoverflow
Solution 8 - JavaKanagavelu SugumarView Answer on Stackoverflow
Solution 9 - JavaAlexRView Answer on Stackoverflow