Generando UUID de solo 8 caracteres

Las bibliotecas UUID generan UUID de 32 caracteres.

Quiero generar UUID de solo 8 caracteres, ¿es posible?

No es posible dado que un UUID es un número de 16 bytes por definición. Pero, por supuesto, puede generar cadenas únicas largas de 8 caracteres (vea las otras respuestas).

También tenga cuidado al generar UUID más largos y subscribirlos, ya que algunas partes de la ID pueden contener bytes fijos (por ejemplo, este es el caso de los UUID MAC, DCE y MD5).

Puedes probar la clase RandomStringUtils desde apache.commons :

 import org.apache.commons.lang3.RandomStringUtils; final int SHORT_ID_LENGTH = 8; // all possible unicode characters String shortId = RandomStringUtils.random(SHORT_UID_LENGTH); 

Tenga en cuenta que contendrá todos los caracteres posibles que no sean ni URL ni humanos.

Entonces, revise otros métodos también:

 // HEX: 0-9, af. For example: 6587fddb, c0f182c1 shortId = RandomStringUtils.random(8, "0123456789abcdef"); // az, AZ. For example: eRkgbzeF, MFcWSksx shortId = RandomStringUtils.randomAlphabetic(8); // 0-9. For example: 76091014, 03771122 shortId = RandomStringUtils.randomNumeric(8); // az, AZ, 0-9. For example: WRMcpIk7, s57JwCVA shortId = RandomStringUtils.randomAlphanumeric(8); 

Como otros dijeron, la probabilidad de una colisión de id con ID más pequeña puede ser significativa. Vea cómo se aplica el problema de cumpleaños a su caso. Puedes encontrar una buena explicación sobre cómo calcular la aproximación en esta respuesta .

Primero: incluso los ID únicos generados por java UUID.randomUUID o .NET GUID no son 100% únicos. Especialmente UUID.randomUUID es “solo” un valor aleatorio de 128 bits (seguro). Entonces, si lo reduce a 64 bits, 32 bits, 16 bits (o incluso 1 bit), entonces se vuelve simplemente menos único.

Por lo tanto, es al menos una decisión basada en el riesgo, por cuánto tiempo debe permanecer.

Segundo: supongo que cuando hablas de “solo 8 caracteres” te refieres a una Cadena de 8 caracteres imprimibles normales.

Si desea una cadena única con caracteres imprimibles de longitud 8, puede usar una encoding base64. Esto significa 6 bits por char, por lo que obtienes 48 bits en total (posiblemente no muy único, pero tal vez esté bien para tu aplicación)

Entonces, el camino es simple: crear una matriz aleatoria de 6 bytes

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

Y luego, transfórmalo a una Cadena Base64, por ejemplo, por org.apache.commons.codec.binary.Base64

Por cierto: depende de tu aplicación si hay una mejor manera de crear “uuid” que de forma aleatoria. (Si crea los UUID solo una vez por segundo, entonces es una buena idea agregar un sello de tiempo) (Por cierto: si combina (xor) dos valores aleatorios, el resultado siempre será al menos tan aleatorio como el más al azar de los dos).

Como @Cephalopod declaró que no es posible, pero puede acortar un UUID a 22 caracteres

 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()), '='); } 

Esta es una forma similar que estoy usando aquí para generar un código de error único, basado en la respuesta de Anton Purin, pero confiando en org.apache.commons.text.RandomStringGenerator lugar de la obsoleta org.apache.commons.lang3.RandomStringUtils :

 @Singleton @Component public class ErrorCodeGenerator implements Supplier { 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); } } 

Todos los consejos sobre colisión aún se aplican, por favor tenga en cuenta.

En realidad, quiero un identificador único más corto basado en la marca de tiempo, por lo tanto, probé el progtwig a continuación.

Se puede adivinar con combinaciones de nanosecond + ( endians.length * endians.length ) .

 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 threadLocal = new ThreadLocal(); 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 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(); } } 

ACTUALIZACIÓN : Este código funcionará en JVM única, pero deberíamos pensar en JVM distribuida, por lo tanto, estoy pensando en dos soluciones, una con DB y otra sin DB.

con DB

Nombre de la empresa (shortname 3 chars) —- Random_Number —- Key specific redis COUNTER
(3 caracteres) ———————————————- – (2 caracteres) —————- (11 caracteres)

sin DB

IPADDRESS —- THREAD_NUMBER —- INCR_NUMBER —- epoch miliseconds
(5 caracteres) —————– (2char) ———————– (2 caracteres ) —————– (6 caracteres)

lo actualizará una vez que la encoding esté completa.

¿Que tal este? En realidad, este código devuelve 13 caracteres como máximo, pero es más corto que 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); } 

No creo que sea posible, pero tienes una buena solución.

  1. cortar el final de su UUID utilizando subcadena ()
  2. use el código new Random(System.currentTimeMillis()).nextInt(99999999); esto generará una identificación aleatoria de hasta 8 caracteres.
  3. generar ID alfanumérico:

     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);