UUID-Bibliotheken generieren UUIDs mit 32 Zeichen.
Ich möchte nur UUIDs mit 8 Zeichen generieren. Ist das möglich?
UUID-Bibliotheken generieren UUIDs mit 32 Zeichen.
Ich möchte nur UUIDs mit 8 Zeichen generieren. Ist das möglich?
Antworten:
Dies ist nicht möglich, da eine UUID eine 16-Byte-Zahl pro Definition ist. Natürlich können Sie auch 8 Zeichen lange eindeutige Zeichenfolgen generieren (siehe die anderen Antworten).
Seien Sie auch vorsichtig beim Generieren längerer UUIDs und deren Teilzeichenfolge, da einige Teile der ID feste Bytes enthalten können (z. B. ist dies bei MAC-, DCE- und MD5-UUIDs der Fall).
Sie können die RandomStringUtils
Klasse von apache.commons aus versuchen :
import org.apache.commons.lang3.RandomStringUtils;
final int SHORT_ID_LENGTH = 8;
// all possible unicode characters
String shortId = RandomStringUtils.random(SHORT_ID_LENGTH);
Bitte beachten Sie, dass es alle möglichen Zeichen enthält, die weder URL noch menschlich sind.
Schauen Sie sich auch andere Methoden an:
// 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);
Wie andere sagten, kann die Wahrscheinlichkeit einer ID-Kollision mit einer kleineren ID signifikant sein. Überprüfen Sie, wie das Geburtstagsproblem auf Ihren Fall zutrifft. In dieser Antwort finden Sie eine gute Erklärung zur Berechnung der Approximation .
org.apache.commons.lang3.RandomStringUtils
es veraltet ist, sollten Sie es besser org.apache.commons.text.RandomStringGenerator
in commons.apache.org/proper/commons-text
RandomStringGenerator
, da es sich um einen ganz anderen Code handelt.
RandomStringUtils
ist NICHT veraltet. Es ist für den einfachen Gebrauch gedacht. Können Sie eine Quelle für RandomStringUtils
veraltete Informationen angeben? Ich kann die Dokumentation der neuesten Version von RandomStringUtils
als Beweis dafür bereitstellen,
Erstens: Selbst die von Java UUID.randomUUID oder .net GUID generierten eindeutigen IDs sind nicht 100% eindeutig. Insbesondere UUID.randomUUID ist "nur" ein 128-Bit-Zufallswert (sicher). Wenn Sie es also auf 64 Bit, 32 Bit, 16 Bit (oder sogar 1 Bit) reduzieren, wird es einfach weniger eindeutig.
Es ist also zumindest eine risikobasierte Entscheidung, wie lange Ihre UUID sein muss.
Zweitens: Ich gehe davon aus, dass Sie, wenn Sie von "nur 8 Zeichen" sprechen, eine Zeichenfolge mit 8 normal druckbaren Zeichen meinen.
Wenn Sie eine eindeutige Zeichenfolge mit druckbaren Zeichen der Länge 8 möchten, können Sie eine base64-Codierung verwenden. Dies bedeutet 6 Bit pro Zeichen, sodass Sie insgesamt 48 Bit erhalten (möglicherweise nicht sehr eindeutig - aber möglicherweise ist es für Ihre Anwendung in Ordnung).
Der Weg ist also einfach: Erstellen Sie ein 6-Byte-Zufallsarray
SecureRandom rand;
// ...
byte[] randomBytes = new byte[16];
rand.nextBytes(randomBytes);
Und transformieren Sie es dann in einen Base64-String, zum Beispiel von org.apache.commons.codec.binary.Base64
Übrigens: Es hängt von Ihrer Anwendung ab, ob es einen besseren Weg gibt, "uuid" als zufällig zu erstellen. (Wenn Sie die UUIDs nur einmal pro Sekunde erstellen, empfiehlt es sich, einen Zeitstempel hinzuzufügen.) (Übrigens: Wenn Sie (xor) zwei Zufallswerte kombinieren, ist das Ergebnis immer mindestens so zufällig wie die meisten zufällig von beiden).
Wie @Cephalopod sagte, ist dies nicht möglich, aber Sie können eine UUID auf 22 Zeichen kürzen
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()), '=');
}
Dies ist eine ähnliche Methode, mit der ich hier einen eindeutigen Fehlercode generiere, der auf der Antwort von Anton Purin basiert, sich jedoch auf den angemesseneren org.apache.commons.text.RandomStringGenerator
anstelle des (einmal, nicht mehr) veralteten Codes stützt 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);
}
}
Alle Hinweise zur Kollision gelten weiterhin, bitte beachten Sie diese.
RandomStringUtils
ist NICHT veraltet. Es ist für den einfachen Gebrauch gedacht. Können Sie eine Quelle für RandomStringUtils
veraltete Informationen angeben? Ich kann die Dokumentation der neuesten Version von RandomStringUtils
als Beweis dafür bereitstellen,
commons.lang
, das ohnehin nicht eng mit der Sprache selbst zusammenhängt und commons.text
mit einem Zweck erstellt wurde.
RandomStringUtils
ist es nicht veraltet und gemäß den von Ihnen angegebenen Referenzen gibt es einen guten Grund, es nicht veraltet zu halten, da es viel einfacher zu verwenden ist als RandomStringGenerator
für einfache Anwendungsfälle. Vielleicht können Sie Ihre Antwort aktualisieren? Wenn / wann RandomStringUtils
oder seine Funktionalität für einfache Anwendungsfälle verschoben wird commons.text
, können Sie Ihre Antwort erneut aktualisieren, aber derzeit ist sie irreführend.
commons.lang
nach verschiebt commons.text
. Es gibt keinen Grund für jemanden, das erstere anstelle des letzteren zu verwenden, außer es bereits an einem anderen Ort zu verwenden. Die Einfachheit hier ist eher subjektiv, ich finde meine Antwort immer noch sehr einfach, und ich würde sie niemals gegen etwas ändern, für das der Import von Commons Lang erforderlich wäre.
Wie wäre es mit diesem? Tatsächlich gibt dieser Code maximal 13 Zeichen zurück, ist jedoch kürzer als die 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()
nur die ersten 8 Bytes des Puffers gelesen werden. Die UUID hat mindestens 36 Bytes. Vermisse ich etwas, weil das für mich niemals funktionieren würde?
Long.toString(uuid.getLessSignificantBits(), Character.MAX_RADIX)
also besser.
Eigentlich möchte ich eine zeitstempelbasierte kürzere eindeutige Kennung, daher habe ich das folgende Programm ausprobiert.
Es ist mit nanosecond + ( endians.length * endians.length )
Kombinationen zu erraten .
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 : Dieser Code funktioniert mit einer einzelnen JVM, aber wir sollten an eine verteilte JVM denken, daher denke ich an zwei Lösungen, eine mit DB und eine ohne DB.
mit DB
Firmenname (Kurzname 3 Zeichen) ---- Random_Number ---- Schlüsselspezifische Redis COUNTER
(3 Zeichen ) -------------------------- ---------------------- (2 Zeichen) ---------------- (11 Zeichen)
ohne DB
IPADDRESS ---- THREAD_NUMBER ---- INCR_NUMBER ---- Epoche Millisekunden
(5 Zeichen) ----------------- (2 Zeichen) --------- -------------- (2 Zeichen) ----------------- (6 Zeichen)
wird Sie aktualisieren, sobald die Codierung abgeschlossen ist.
Keine UUID, aber das funktioniert bei mir:
UUID.randomUUID().toString().replace("-","").substring(0,8)
Ich denke nicht, dass es möglich ist, aber Sie haben eine gute Problemumgehung.
new Random(System.currentTimeMillis()).nextInt(99999999);
, um eine zufällige ID mit einer Länge von bis zu 8 Zeichen zu generieren.alphanumerische ID generieren:
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);