Библиотеки UUID генерируют 32-символьные UUID.
Я хочу сгенерировать только 8-символьные UUID, возможно ли это?
Библиотеки UUID генерируют 32-символьные UUID.
Я хочу сгенерировать только 8-символьные UUID, возможно ли это?
Ответы:
Это невозможно, поскольку UUID - это 16-байтовое число на определение. Но, конечно, вы можете сгенерировать уникальные строки длиной 8 символов (см. Другие ответы).
Также будьте осторожны с генерацией более длинных UUID и их подстрокой, поскольку некоторые части идентификатора могут содержать фиксированные байты (например, это имеет место с UUID MAC, DCE и MD5).
Вы можете попробовать 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 символа) ---- Случайное_номер ---- Ключевой 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);