Библиотеки 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);
Как говорили другие, вероятность столкновения идентификатора с меньшим идентификатором может быть значительной. Проверьте, как проблема дня рождения относится к вашему делу. Вы можете найти хорошее объяснение, как рассчитать приближение в этом ответе.
Во-первых: даже уникальные идентификаторы, сгенерированные java UUID.randomUUID или .net GUID, не являются 100% уникальными. Especialy UUID.randomUUID - это "только" 128-разрядное (безопасное) случайное значение. Поэтому, если вы уменьшите его до 64 бит, 32 бит, 16 бит (или даже 1 бит), тогда он станет просто менее уникальным.
Итак, это, по крайней мере, основанные на риске решения, как долго ваш uuid должен быть.
Во-вторых: я предполагаю, что когда вы говорите о "только 8 символах", вы имеете в виду строку из 8 обычных печатных символов.
Если вам нужна уникальная строка длиной 8 печатных символов, вы можете использовать кодировку base64. Это означает, что 6 бит на char, поэтому вы получаете всего 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);
}
}
Все советы о столкновении все еще применяются, пожалуйста, имейте в виду.
На самом деле, я хочу, чтобы более короткий уникальный идентификатор на основе временной метки, поэтому пробовал программу ниже.
Это возможно с помощью комбинаций 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. Этот код будет работать на одном JVM, но мы должны подумать о распределенной JVM, поэтому я думаю о двух решениях с DB и еще одном без DB.
с DB
Название компании (короткое имя 3 символа) ---- Random_Number ---- Ключ, специфичный для redis COUNTER
(3 char) -------------------------------------------- ---- (2 char) ---------------- (11 char)
без DB
IPADDRESS ---- THREAD_NUMBER ---- INCR_NUMBER ---- epoch milliseconds
(5 символов) ----------------- (2char) ----------------------- (2 char) ----------------- (6 char)
обновит вас после завершения кодирования.
Как насчет этого? Фактически, этот код возвращает максимум 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);
}
Я не думаю, что это возможно, но у вас есть хорошее обходное решение.
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);