UUIDライブラリは32文字のUUIDを生成します。
8文字のみのUUIDを生成したいのですが、可能ですか?
UUIDライブラリは32文字のUUIDを生成します。
8文字のみの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);
他の人が言ったように、より小さなIDとのID衝突の確率は重要である可能性があります。誕生日の問題があなたのケースにどのように当てはまるかを確認してください。あなたはこの答えで近似を計算する方法の良い説明を見つけることができます。
org.apache.commons.lang3.RandomStringUtils
は非推奨であるためorg.apache.commons.text.RandomStringGenerator
、commons.apache.org
RandomStringGenerator
まったく異なるコードであるため、の新しい回答を追加しました。
RandomStringUtils
非推奨ではありません。簡単な使用を目的としています。RandomStringUtils
非推奨となる情報のソースを提供できますか?私は、最新バージョンのドキュメントを提供することができますRandomStringUtils
:それは廃止されていないことを証明するものとしてcommons.apache.org/proper/commons-lang/javadocs/api-3.9/org/...
まず、javaUUID.randomUUIDまたは.netGUIDによって生成された一意のIDでさえ100%一意ではありません。特にUUID.randomUUIDは、128ビット(セキュア)のランダム値に「のみ」含まれます。したがって、64ビット、32ビット、16ビット(または1ビット)に減らすと、単純に一意性が低下します。
したがって、それは少なくともリスクベースの決定であり、uuidの長さでなければなりません。
2番目:「8文字のみ」とは、通常の印刷可能な8文字の文字列を意味すると思います。
印刷可能な長さが8文字の一意の文字列が必要な場合は、base64エンコーディングを使用できます。これは、1文字あたり6ビットを意味するため、合計で48ビットになります(あまりユニークではない可能性がありますが、アプリケーションには問題ないかもしれません)
したがって、方法は簡単です。6バイトのランダム配列を作成します。
SecureRandom rand;
// ...
byte[] randomBytes = new byte[16];
rand.nextBytes(randomBytes);
そして、それをBase64文字列に変換します。 org.apache.commons.codec.binary.Base64
ところで:「uuid」をランダムに作成するより良い方法があるかどうかは、アプリケーションによって異なります。(UUIDを1秒に1回だけ作成する場合は、タイムスタンプを追加することをお勧めします)(ちなみに、2つのランダムな値を(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()), '=');
}
これは、Anton Purinの回答に基づいて、一意のエラーコードを生成するためにここで使用しているのと同様の方法です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
です。すでに別の場所で使用している以外に、後者ではなく前者を使用する理由はありません。ここでの単純さはかなり主観的なものであり、私の答えはまだ非常に単純であり、CommonsLangをインポートする必要があるものに変更することは決してありません。
これはどう?実際、このコードは最大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バイトが含まれます。私にはこれがうまくいかないので、私は何かが欠けていますか?
実際、タイムスタンプベースのより短い一意の識別子が必要なので、以下のプログラムを試してみました。
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について考える必要があるため、DBを使用するソリューションとDBを使用しないソリューションの2つのソリューションを考えています。
DB付き
会社名(短縮名3文字)---- Random_Number ----キー固有のredisCOUNTER
(3文字)-------------------------- ----------------------(2文字)----------------(11文字)
DBなし
IPADDRESS ---- THREAD_NUMBER ---- INCR_NUMBER ----エポックミリ秒
(5文字)-----------------(2文字)--------- --------------(2文字)-----------------(6文字)
コーディングが完了すると更新されます。
UUIDではありませんが、これは私にとってはうまくいきます:
UUID.randomUUID().toString().replace("-","").substring(0,8)
私はそれが可能だとは思いませんが、あなたには良い回避策があります。
new Random(System.currentTimeMillis()).nextInt(99999999);
と、最大8文字のランダムIDが生成されます。英数字IDを生成します:
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);