Las bibliotecas de UUID generan UUID de 32 caracteres.
Quiero generar UUID de solo 8 caracteres, ¿es posible?
Las bibliotecas de UUID generan UUID de 32 caracteres.
Quiero generar UUID de solo 8 caracteres, ¿es posible?
Respuestas:
No es posible porque un UUID es un número de 16 bytes por definición. Pero, por supuesto, puede generar cadenas únicas de 8 caracteres de largo (consulte las otras respuestas).
También tenga cuidado con generar UUID más largos y subcadenas, ya que algunas partes del ID pueden contener bytes fijos (por ejemplo, este es el caso de los UUID MAC, DCE y MD5).
Puede probar la RandomStringUtils
clase de 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);
Tenga en cuenta que contendrá todos los caracteres posibles que no son ni URL ni amigables para los humanos.
Así que echa un vistazo a otros métodos también:
// 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);
Como dijeron otros, la probabilidad de colisión de identificación con identificación más pequeña puede ser significativa. Vea cómo se aplica el problema del cumpleaños a su caso. Puede encontrar una buena explicación sobre cómo calcular la aproximación en esta respuesta .
org.apache.commons.lang3.RandomStringUtils
está en desuso, sería mejor usar org.apache.commons.text.RandomStringGenerator
en commons.apache.org/proper/commons-text
RandomStringGenerator
, ya que es un código bastante diferente.
RandomStringUtils
NO está en desuso. Está destinado a un uso sencillo. ¿Puede proporcionar una fuente de información RandomStringUtils
obsoleta? Puedo proporcionar la documentación de la última versión de RandomStringUtils
como prueba de que no está obsoleta: commons.apache.org/proper/commons-lang/javadocs/api-3.9/org/…
Primero: Incluso los ID únicos generados por java UUID.randomUUID o .net GUID no son 100% únicos. Especialmente UUID.randomUUID es "sólo" un valor aleatorio de 128 bits (seguro). Entonces, si lo reduce a 64 bits, 32 bits, 16 bits (o incluso 1 bit), simplemente se vuelve menos único.
Por lo tanto, es al menos una decisión basada en el riesgo, la duración de su uuid.
Segundo: supongo que cuando habla de "solo 8 caracteres" se refiere a una cadena de 8 caracteres imprimibles normales.
Si desea una cadena única con una longitud de 8 caracteres imprimibles, puede usar una codificación base64. Esto significa 6 bits por carácter, por lo que obtiene 48 bits en total (es posible que no sea muy único, pero tal vez esté bien para su aplicación)
Entonces la forma es simple: cree una matriz aleatoria de 6 bytes
SecureRandom rand;
// ...
byte[] randomBytes = new byte[16];
rand.nextBytes(randomBytes);
Y luego transfórmalo en una Cadena Base64, por ejemplo, org.apache.commons.codec.binary.Base64
Por cierto: depende de su aplicación si hay una mejor manera de crear "uuid" que al azar. (Si crea un UUID solo una vez por segundo, entonces es una buena idea agregar una marca de tiempo) (Por cierto: si combina (xor) dos valores aleatorios, el resultado siempre es al menos tan aleatorio como la mayoría aleatorio de los dos).
Como dijo @Cephalopod, 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 el más apropiado en org.apache.commons.text.RandomStringGenerator
lugar del (una vez, ya no) en desuso 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);
}
}
Todos los consejos sobre colisión siguen siendo válidos, por favor, téngalos en cuenta.
RandomStringUtils
NO está en desuso. Está destinado a un uso sencillo. ¿Puede proporcionar una fuente de información RandomStringUtils
obsoleta? Puedo proporcionar la documentación de la última versión de RandomStringUtils
como prueba de que no está obsoleta: commons.apache.org/proper/commons-lang/javadocs/api-3.9/org/…
commons.lang
que no esté estrictamente relacionado con el lenguaje en sí, que commons.text
fue creado con un propósito.
RandomStringUtils
no está en desuso y de acuerdo con las referencias proporcionadas por usted, hay una buena razón para mantenerlo en desuso, porque es mucho más simple de usar que RandomStringGenerator
para casos de uso simples. ¿Quizás puedas actualizar tu respuesta? Si / cuando RandomStringUtils
o su funcionalidad para casos de uso simples se moverá a commons.text
, entonces puede actualizar su respuesta nuevamente, pero actualmente es engañoso.
commons.lang
a commons.text
, no hay ninguna razón para que alguien use la primera en lugar de la última, aparte de que ya la esté usando en otro lugar. La simplicidad aquí es bastante subjetiva, encuentro que mi respuesta sigue siendo muy simple y nunca la cambiaría por algo que requiera la importación de Commons Lang.
¿Que tal este? En realidad, este código devuelve un máximo de 13 caracteres, pero es más corto que el 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);
}
getLong()
solo está leyendo los primeros 8 bytes del búfer. El UUID tendrá al menos 36 bytes. ¿Me estoy perdiendo algo porque para mí esto nunca funcionaría?
Long.toString(uuid.getLessSignificantBits(), Character.MAX_RADIX)
es mejor.
En realidad, quiero un identificador único más corto basado en la marca de tiempo, por lo tanto, probé el siguiente programa.
Es adivinable con nanosecond + ( endians.length * endians.length )
combinaciones.
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();
}
}
ACTUALIZACIÓN : Este código funcionará en una sola JVM, pero deberíamos pensar en una JVM distribuida, por lo tanto, estoy pensando en dos soluciones, una con DB y otra sin DB.
con DB
Nombre de la empresa (nombre abreviado 3 caracteres) ---- Número_aleatorio ---- Clave redis específica CONTADOR
(3 caracteres) -------------------------- ---------------------- (2 caracteres) ---------------- (11 caracteres)
sin DB
IPADDRESS ---- THREAD_NUMBER ---- INCR_NUMBER ---- epoch milisegundos
(5 caracteres) ----------------- (2char) --------- -------------- (2 caracteres) ----------------- (6 caracteres)
lo actualizará una vez que finalice la codificación.
No es un UUID, pero esto funciona para mí:
UUID.randomUUID().toString().replace("-","").substring(0,8)
No creo que sea posible, pero tienes una buena solución.
new Random(System.currentTimeMillis()).nextInt(99999999);
esto generará una identificación aleatoria de hasta 8 caracteres de largo.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);