Ne générant que des UUID à 8 caractères
génèrent des UUID de 32 caractères.
je veux générer des UUID à 8 caractères seulement, est-ce possible?
8 réponses
ce n'est pas possible car un UUID est un nombre de 16 octets par définition. mais bien sûr, vous pouvez générer de longues chaînes uniques de 8 caractères (voir les autres réponses).
veillez également à générer des UUIDs plus longs et à les soustraire, car certaines parties de L'ID peuvent contenir des octets fixes (par exemple, C'est le cas pour les UUIDs MAC, DCE et MD5).
vous pouvez essayer la classe RandomStringUtils
d'apache.communes :
import org.apache.commons.lang3.RandomStringUtils;
final int SHORT_ID_LENGTH = 8;
// all possible unicode characters
String shortId = RandomStringUtils.random(SHORT_UID_LENGTH);
s'il vous plaît gardez à l'esprit, qu'il contiendra tous les caractères possibles qui n'est ni URL ni human friendly.
donc vérifier d'autres méthodes aussi:
// 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);
comme d'autres l'ont dit, la probabilité d'une collision id avec un id plus petit peut être significative. Découvrez comment problème d'anniversaire s'applique à votre cas. Vous pouvez trouver une explication agréable comment calculer approximation dans cette réponse .
D'abord: même les identifiants uniques générés par java UUID.randomUUID ou. net GUID ne sont pas 100% uniques. Spécialement UUID.randomUUID est "seulement" une valeur aléatoire de 128 bits (sécurisée). Donc si vous le réduisez à 64 bits, 32 bits, 16 bits (ou même 1 bit) alors il devient tout simplement moins unique.
donc c'est au moins une décision basée sur le risque, combien de temps votre uuid doit être.
Deuxième: je suppose que lorsque vous parlez de "seulement 8 caractères" vous voulez dire une Chaîne de 8 normal caractères imprimables.
Si vous voulez une chaîne unique avec une longueur de 8 caractères imprimables, vous pouvez utiliser un encodage base64. Cela signifie 6bit par char, donc vous obtenez 48bit au total (possible pas très unique - mais peut-être il est ok pour votre application)
donc la voie est simple: créer un tableau aléatoire de 6 octets
SecureRandom rand;
// ...
byte[] randomBytes = new byte[16];
rand.nextBytes(randomBytes);
et ensuite le transformer en chaîne de Base64, par exemple par org.apache.commons.codec.binary.Base64
BTW: cela dépend sur votre application s'il y a une meilleure façon de créer "uuid" puis par hasard. (Si vous créez une l'Uuid qu'une seule fois par seconde, alors c'est une bonne idée d'ajouter un horodatage) (En passant: si vous combinez (xor) deux valeurs aléatoires, le résultat est toujours au moins aussi aléatoire que le plus aléatoire de la les deux).
comme @Cephalopod a déclaré que ce n'est pas possible, mais vous pouvez raccourcir un UUID à 22 caractères
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()), '=');
}
c'est une façon similaire que j'utilise ici pour générer un code d'erreur unique, basé sur la réponse D'Anton Purin, mais en se basant sur org.apache.commons.text.RandomStringGenerator
au lieu de l'déprécié 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);
}
}
Tous les conseils sur la collision s'appliquent toujours, s'il vous plaît être conscient.
en fait je veux timestamp basé identificateur unique plus court, donc essayé le programme ci-dessous.
c'est une supposition avec les combinaisons 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<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 : ce code fonctionnera sur une seule JVM, mais nous devrions penser à une JVM distribuée, donc je pense à deux solutions l'une avec DB et l'autre sans DB.
avec DB
nom de L'entreprise (Nom abrégé 3 caractères) ---- Random_Number ---- Clé spécifique redis COMPTEUR
(3 char) ------------------------------------------------ (2 char) ---------------- (11 char)
sans DB
IPADDRESS ---- THREAD_NUMBER ---- INCR_NUMBER - - - - epoch millisecondes
(5 caractères) ----------------- (2char) ----------------------- (2 char) ----------------- (6 char)
vous mettra à jour une fois que le codage est faire.
et celui-ci? En fait, ce code renvoie 13 caractères max, mais il est plus court 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);
}
je ne pense pas que c'est possible, mais vous avez une bonne solution.
- couper l'extrémité de votre UUID en utilisant le substrat ()
- code d'utilisation
new Random(System.currentTimeMillis()).nextInt(99999999);
cela générera des identifiants aléatoires jusqu'à 8 caractères de long. -
générer de l'identification alphanumérique:
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);