Бібліотеки UUID генерують 32-символьні UUID.
Я хочу створити 8-символьні UUID, чи можливо це?
Бібліотеки UUID генерують 32-символьні UUID.
Я хочу створити 8-символьні UUID, чи можливо це?
Відповіді:
Це неможливо, оскільки UUID - це 16-байтове число для визначення. Але, звичайно, ви можете генерувати унікальні рядки довжиною 8 символів (див. Інші відповіді).
Також будьте обережні із створенням довших UUID та їх підрядком, оскільки деякі частини ідентифікатора можуть містити фіксовані байти (наприклад, це стосується MAC, DCE та MD5 UUID).
Ви можете спробувати RandomStringUtils
клас з 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);
Будь ласка, майте на увазі, що він буде містити всі можливі символи, які не є ані URL-адресами, ані зручними для людей.
Тож перевірте й інші методи:
// 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);
Як казали інші, ймовірність зіткнення ІД з меншим ІД може бути значною. Перевірте, як проблема народження стосується вашої справи. У цій відповіді ви знайдете гарне пояснення, як обчислити наближення .
org.apache.commons.lang3.RandomStringUtils
застарілий, вам було б краще використовувати його org.apache.commons.text.RandomStringGenerator
в commons.apache.org/proper/commons-text
RandomStringGenerator
, оскільки це зовсім інший код.
RandomStringUtils
не є застарілою. Він призначений для простого використання. Чи можете ви надати джерело інформації, яка RandomStringUtils
застаріла? Я можу надати документацію останньої версії RandomStringUtils
як доказ того, що вона не застаріла: commons.apache.org/proper/commons-lang/javadocs/api-3.9/org/…
По-перше: Навіть унікальні ідентифікатори, створені java UUID.randomUUID або .net GUID, не є на 100% унікальними. Особливий UUID.randomUUID - це "лише" 128-бітове (захищене) випадкове значення. Отже, якщо ви зменшите його до 64 біт, 32 біт, 16 біт (або навіть 1 біт), то він стане просто менш унікальним.
Отже, це принаймні рішення, засноване на оцінці ризику, скільки часу має бути ваш uuid.
По-друге: я припускаю, що коли ви говорите про "лише 8 символів", ви маєте на увазі рядок із 8 звичайних символів для друку.
Якщо вам потрібен унікальний рядок довжиною 8 друкованих символів, ви можете використовувати кодування base64. Це означає 6 біт на символ, тож ви отримуєте 48 біт загалом (можливо, не дуже унікально - але, можливо, це нормально для вашої програми)
Тож шлях простий: створіть 6-байтовий випадковий масив
SecureRandom rand;
// ...
byte[] randomBytes = new byte[16];
rand.nextBytes(randomBytes);
А потім перетворіть його на рядок Base64, наприклад org.apache.commons.codec.binary.Base64
До речі: від вашої програми залежить, чи є кращий спосіб створити "uuid", а не випадковим чином. (Якщо ви створюєте UUID лише один раз на секунду, тоді непогано додати позначку часу) (До речі: якщо ви поєднуєте (xor) два випадкові значення, результат завжди є принаймні таким випадковим, як найбільш випадкові з обох).
Як зазначив @Cephalopod, це неможливо, але ви можете скоротити UUID до 22 символів
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()), '=');
}
Це подібний спосіб, який я використовую тут для створення унікального коду помилки, заснованого на відповіді Антона Пуріна, але покладаючись на більш доречний org.apache.commons.text.RandomStringGenerator
замість (колись, не більше) застарілого 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);
}
}
Усі поради щодо зіткнення все ще застосовуються, будь ласка, пам’ятайте про них.
RandomStringUtils
не є застарілою. Він призначений для простого використання. Чи можете ви надати джерело інформації, яка RandomStringUtils
застаріла? Я можу надати документацію останньої версії RandomStringUtils
як доказ того, що вона не застаріла: commons.apache.org/proper/commons-lang/javadocs/api-3.9/org/…
commons.lang
що так чи інакше не суворо пов'язане з самою мовою, commons.text
створене з певною метою.
RandomStringUtils
не є застарілою, і відповідно до наданих вами посилань є вагома причина, щоб тримати його не застарілим, оскільки він набагато простіший у використанні, ніж RandomStringGenerator
для простих випадків використання. Можливо, ви можете оновити свою відповідь? Якщо / коли RandomStringUtils
або його функціональні можливості для простих випадків використання будуть перенесені commons.text
, тоді ви можете оновити свою відповідь ще раз, але наразі це оманливе повідомлення.
commons.lang
на commons.text
, немає жодної причини для того, щоб хтось використовував перший, а не другий, крім того, що вже використовував його десь ще. Тут простота досить суб’єктивна, я вважаю, що моя відповідь все ще дуже проста, і я ніколи не зміню її на щось, що вимагає імпорту Commons Lang.
Як щодо цього? Насправді цей код повертає максимум 13 символів, але він коротший за 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()
читається лише перші 8 байт буфера. UUID матиме щонайменше 36 байт. Я чогось пропускаю, бо для мене це ніколи не спрацювало б.
Long.toString(uuid.getLessSignificantBits(), Character.MAX_RADIX)
краще.
Насправді я хочу коротший унікальний ідентифікатор на основі мітки часу, тому спробував наведену нижче програму.
Це можна вгадати за допомогою 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();
}
}
ОНОВЛЕННЯ : Цей код буде працювати на одній JVM, але нам слід подумати про розподілену JVM, отже, я думаю про два рішення, одне з БД та інше без БД.
з БД
Назва компанії (скорочена назва 3 символи) ---- Random_Number ---- Ключові слова Redis COUNTER
(3 символи ) -------------------------- ---------------------- (2 символи) ---------------- (11 символів)
без БД
IPADDRESS ---- THREAD_NUMBER ---- INCR_NUMBER ---- епоха мілісекунд
(5 символів) ----------------- (2char) --------- -------------- (2 символи) ----------------- (6 символів)
оновить вас після завершення кодування.
Не UUID, але це працює для мене:
UUID.randomUUID().toString().replace("-","").substring(0,8)
Я не думаю, що це можливо, але у вас є хороший обхідний шлях.
new Random(System.currentTimeMillis()).nextInt(99999999);
це створить випадковий ідентифікатор довжиною до 8 символів.згенерувати буквено-цифровий ідентифікатор:
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);