JAVAでUUID文字列を生成する効率的な方法(ダッシュなしのUUID.randomUUID()。toString())


154

ユニークなバイトシーケンスを生成するための効率的なユーティリティが必要です。UUIDは良い候補ですが、そのUUID.randomUUID().toString()ようなものを生成します44e128a5-ac7a-4c9a-be4c-224b6bf81b20が、私はダッシュなしの文字列を好みます。

英数字のみ(ダッシュやその他の特殊記号なし)からランダムな文字列を生成する効率的な方法を探しています。


38
このようなUUIDをHTTP経由で送信するには、なぜダッシュを削除する必要があるのですか?
Bruno

6
HTTPでダッシュを削除する必要があるとは一般的には思いませんでした...どのビットが面倒の原因ですか?
Jon Skeet

2
おそらくモバイル環境で、送信バイトごとに支払いを行い、低帯域幅で高遅延のネットワークを使用する場合、一部のシナリオでは4バイトを節約することが重要です...
Guido

2
ダッシュを削除してほしいのは、後でUUID文字列を一意のリクエスト識別子として使用するためです。16進数の10進文字のみを使用すると、[a-f0-9-]を使用する方がはるかに簡単です。
Maxim Veksler、2009

(マキシムが説明したように)関連がないため、読者を混乱させるだけなので(コメントと回答の両方に見られるように)、HTTPの部分を削除しました。
OndraŽižka

回答:


274

これはそれを行います:

public static void main(String[] args) {
    final String uuid = UUID.randomUUID().toString().replace("-", "");
    System.out.println("uuid = " + uuid);
}

たとえば、MongodbはObjectIDでダッシュを使用しません。そのため、ダッシュを削除するとAPIに役立ちます。
Alexey Ryazhskikh

1
理由を説明します。UUIDでダッシュを使用できないAPI(ハイプロファイル、よく知られている)を使用しています。それらを取り除く必要があります。
マイケルゲインズ2015年

19
正規表現を使用するreplaceAllを実行する必要はありません。.replace( "-"、 "")を実行するだけ
クレイゴ2016年

1
Stringクラスのreplaceメソッドは少し遅いと思います
bmscomp

@bmscompは最初の呼び出しでは遅くなりますが、次の呼び出しでは問題はありません。
gaurav

30

このスレッドのURLで確認できるように、HTTPリクエストからダッシュを削除する必要はありません。ただし、データに依存せずに整形式のURLを準備する場合は、データの標準形式を変更する代わりに、URLEncoder.encode(String data、String encoding)を使用する必要があります。UUID文字列表現の場合、ダッシュは正常です。


「このスレッドのURLで確認できるように、HTTPリクエストからダッシュを削除する必要はありません。」Stack Overflowが以前にURLでUUIDを使用していない限り、理解できませんか?
RenniePet 2014

1
URLがUUIDであることではなく、ダッシュが含まれていることhttp://stackoverflow.com/questions/3804591/efficient-method-to-generate-uuid-string-in-java-uuid-randomuuid-tostring-w?rq=1
Octavia Togami

12

結局、UUID.java実装に基づいて独自の何かを書くことになりました。私がUUIDを生成しているわけでないことに注意してください。代わりに、私が考えることができる最も効率的な方法でランダムな32バイトの16進文字列を生成します。

実装

import java.security.SecureRandom;
import java.util.UUID;

public class RandomUtil {
    // Maxim: Copied from UUID implementation :)
    private static volatile SecureRandom numberGenerator = null;
    private static final long MSB = 0x8000000000000000L;

    public static String unique() {
        SecureRandom ng = numberGenerator;
        if (ng == null) {
            numberGenerator = ng = new SecureRandom();
        }

        return Long.toHexString(MSB | ng.nextLong()) + Long.toHexString(MSB | ng.nextLong());
    }       
}

使用法

RandomUtil.unique()

テスト

動作することを確認するためにテストした入力の一部:

public static void main(String[] args) {
    System.out.println(UUID.randomUUID().toString());
    System.out.println(RandomUtil.unique());

    System.out.println();
    System.out.println(Long.toHexString(0x8000000000000000L |21));
    System.out.println(Long.toBinaryString(0x8000000000000000L |21));
    System.out.println(Long.toHexString(Long.MAX_VALUE + 1));
}

1
なぜこれがより支持されているのかわからない、ここで記述されたすべてのオプションから最も効率的な方法で「-」なしで生成されたUUID 文字列の置換は、長い文字列から文字列への変換よりも優れています。どちらもO(n)であることは事実ですが、1分間に何百万ものuuidを生成する規模では、意味があります。
Maxim Veksler

10

JUG(Java UUID Generator)を使用して一意のIDを生成しました。これはJVM全体で一意です。かなり使いやすいです。あなたの参照のためのコードはここにあります:

private static final SecureRandom secureRandom = new SecureRandom();
private static final UUIDGenerator generator = UUIDGenerator.getInstance();

public synchronized static String generateUniqueId() {
  UUID uuid = generator.generateRandomBasedUUID(secureRandom);

  return uuid.toString().replaceAll("-", "").toUpperCase();
}

ライブラリはhttps://github.com/cowtowncoder/java-uuid-generatorからダウンロードできます


あなたの場合、UUID.randomUUID()。toString()の何が問題になっていますか?また、静的な最終SecureRandomを保持することで(理論的には)エントロピーを減少させる(揮発性にする)ことにも注意してください。また、なぜgenerateUniqueIdを同期させるのですか?つまり、このメソッドではすべてのスレッドがブロックされます。
Maxim Veksler、2009

まず第一に、SafehausはJUGの方が速いと主張しています。また、不要なマシン間で一意のIDを生成できます。彼らはすべての方法の中で最もファットなものである時間ベースの方法を持っています。はい、ここでは同期は必要ありません。SecureRandomはすでにスレッドセーフであることに気付きました。SecureRandomでstatic finalを宣言すると、エントロピーが減少するのはなぜですか?私は興味があります:)ここに詳細があります:jug.safehaus.org/FAQ
Sheng Chien

JUGは乱数ベースのUUIDも生成できます。しかし、開発者が時間ベースのバリアントの使用を好む主な理由は、10〜20倍高速であることです(cowtowncoder.com/blog/archives/2010/10/entry_429.html)。または、ランダム性が一意のIDを生成することを信頼しない(これはちょっとおかしい)
StaxMan

jug.safehaus.orgはもう存在しませんが、あなたはでのFAQを見つけることができますraw.github.com/cowtowncoder/java-uuid-generator/3.0/...
ダニエルSerodio

JUGについて言及するための+1-その有用性を確認しましたが、いくつかの深刻なjava.util.UUID代替案があることを知っておくのは良いことです。
Greg Dubicki

8

簡単な解決策は

UUID.randomUUID().toString().replace("-", "")

(既存のソリューションと同様に、String#replaceAll呼び出しを回避するだけです。ここでは正規表現の置換は不要であるため、技術的には正規表現で実装されていますが、String#replaceはより自然に感じられます。UUIDの生成が交換よりも費用がかかりますが、ランタイムに大きな違いはありません。)

UUIDクラスを使用すると、ほとんどのシナリオでおそらく十分高速ですが、後処理を必要としない一部の特殊な手書きのバリアントが高速であることが期待されます。とにかく、全体的な計算のボトルネックは通常、乱数ジェネレーターです。UUIDクラスの場合は、SecureRandomを使用します。

使用する乱数ジェネレーターも、アプリケーションに依存するトレードオフです。セキュリティが重要な場合は、SecureRandomが一般的に推奨されます。それ以外の場合は、ThreadLocalRandomが代わりになります(SecureRandomまたは古いRandomより高速ですが、暗号的に安全ではありません)。


7

多くの文字列がUUIDのアイデアを置き換えるのを見て、私は驚いています。これはどう:

UUID temp = UUID.randomUUID();
String uuidString = Long.toHexString(temp.getMostSignificantBits())
     + Long.toHexString(temp.getLeastSignificantBits());

これは、UUIDのtoString()全体が、解析および実行する必要がある正規表現や空の文字列での置換は言うまでもなく、すでにより高価であるため、これを行う高速な方法です。


6
これは信頼できません。先行ビットが0であれば出力は短くなります
OGデュード

7
String.format("0x%016x%016x", f.getMostSignificantBits(), f.getLeastSignificantBits())
ガレット2016

@galets私は、先頭の0の問題を解決するためにあなたのコメントに賛成票を投じましたが、これを使用してダッシュを置き換える代わりの方法と比較して、これが優れているかどうか疑問に思いreplaceます。
igorcadelima 2017


3

UUID toString()メソッドをコピーし、「-」を削除するために更新しました。他のソリューションよりもはるかに高速で簡単です

public String generateUUIDString(UUID uuid) {
    return (digits(uuid.getMostSignificantBits() >> 32, 8) +
            digits(uuid.getMostSignificantBits() >> 16, 4) +
            digits(uuid.getMostSignificantBits(), 4) +
            digits(uuid.getLeastSignificantBits() >> 48, 4) +
            digits(uuid.getLeastSignificantBits(), 12));
}

/** Returns val represented by the specified number of hex digits. */
private String digits(long val, int digits) {
    long hi = 1L << (digits * 4);
    return Long.toHexString(hi | (val & (hi - 1))).substring(1);
}

使用法:

generateUUIDString(UUID.randomUUID())

リフレクションを使用した別の実装

public String generateString(UUID uuid) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {

    if (uuid == null) {
        return "";
    }

    Method digits = UUID.class.getDeclaredMethod("digits", long.class, int.class);
    digits.setAccessible(true);

    return ( (String) digits.invoke(uuid, uuid.getMostSignificantBits() >> 32, 8) +
            digits.invoke(uuid, uuid.getMostSignificantBits() >> 16, 4) +
            digits.invoke(uuid, uuid.getMostSignificantBits(), 4) +
            digits.invoke(uuid, uuid.getLeastSignificantBits() >> 48, 4) +
            digits.invoke(uuid, uuid.getLeastSignificantBits(), 12));

}

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.