JAVA'da (UUID.randomUUID (). ToString () tire olmadan) UUID Dizesi oluşturmak için etkili yöntem


154

Benzersiz bayt dizileri oluşturmak için verimli bir yardımcı program istiyorum. UUID iyi bir aday ama iyi UUID.randomUUID().toString()gibi şeyler üretiyor 44e128a5-ac7a-4c9a-be4c-224b6bf81b20, ancak çizgi içermeyen dizeyi tercih ederim.

Sadece alfasayısal karakterlerden (tire veya diğer özel semboller) rastgele dizeler oluşturmak için etkili bir yol arıyorum.


38
Böyle bir UUID'nin HTTP üzerinden iletilmesi için neden tire işaretlerinin kaldırılması gerekiyor?
Bruno

6
Dash'lerin HTTP'de genel olarak kaldırılması gerektiğini düşünmedim ... hangi bit size güçlük veriyor?
Jon Skeet

2
Belki mobil bir ortamda, hala iletilen her bayt için ödeme yaparsanız ve düşük bant genişliği ve yüksek gecikmeli bir ağ kullanıyorsanız, bazı senaryolarda 4 bayt tasarrufu hala önemlidir ...
Guido

2
Daha sonra benzersiz istek tanımlayıcı olarak UUID dizesini kullandığımız için tire kaldırılmasını istiyorum, sadece onaltılık ondalık karakterlerle [a-f0-9-] çalışmak çok daha kolay.
Maxim Veksler

HTTP bölümünü kaldırdım çünkü alakalı değil (Maxim'in açıkladığı gibi), sadece okuyucuları karıştırır (hem yorumlarda hem de yanıtlarda görülebileceği gibi).
Ondra Žižka

Yanıtlar:


274

Bunu yapar:

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

Örneğin, Mongodb, ObjectID'de tire kullanmaz. Bu nedenle kısa çizgileri kaldırmak API için yararlı olabilir.
Alexey Ryazhskikh

1
Size bir neden vereceğim. Birlikte çalıştığım bir API (yüksek profilli, iyi bilinen) UUID'sinde tirelere izin vermiyor. Onları soymalısın.
Michael Gaines

19
Değiştirmeye gerek yokTüm, düzenli ifadeler kullanır. Sadece değiştirin .replace ("-", "")
Craigo

1
String sınıfının yerine yöntem biraz yavaş, bence
bmscomp

İlk çağrı için @bmscomp, yavaş, ancak sonraki çağrılar için sorun yok.
gaurav

30

Bu iş parçacığının URL'sinde görebileceğiniz gibi tire işaretlerinin HTTP isteğinden kaldırılması gerekmez. Ancak, verilere bağımlı olmadan iyi biçimlendirilmiş URL hazırlamak istiyorsanız, verilerinizin standart biçimini değiştirmek yerine URLEncoder.encode (String data, String encoding) kullanmalısınız. UUID dizesi temsili çizgileri normaldir.


"Çizgi dizilerinin HTTP isteğinden kaldırılması gerekmez, çünkü bu dizinin URL'sinde görebilirsiniz." Yığın Taşması daha önce URL'lerinde UUID kullanmadığı sürece anlamıyor musunuz?
RenniePet

1
Url bir UUID değil, çizgiler http://stackoverflow.com/questions/3804591/efficient-method-to-generate-uuid-string-in-java-uuid-randomuuid-tostring-w?rq=1
içeriyor

12

UUID.java uygulamasına göre kendime ait bir şeyler yazmayı bitirdim. Ben ediyorum Not Bir UUID oluşturmak değil , bunun yerine sadece rastgele 32 düşünebildiğim en verimli şekilde altıgen dize bayt.

uygulama

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());
    }       
}

kullanım

RandomUtil.unique()

Testler

Çalıştığından emin olmak için test ettiğim bazı girişler:

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
neden daha fazla seçildi emin değilim, bu UUID burada yazılan tüm seçeneklerden en verimli yöntemle "-" olmadan oluşturulan. Dize değiştirme uzuntan dize dönüşüm daha iyi değildir. Her ikisinin de O (n) olduğu doğrudur, ancak milyonlarca uuid ürettiğiniz ölçekte anlamlı hale gelir.
Maxim Veksler

10

Benzersiz kimlik oluşturmak için JUG (Java UUID Generator) kullandım. JVM'ler arasında benzersizdir. Kullanımı oldukça iyi. İşte referans için kod:

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();
}

Kütüphaneyi şu adresten indirebilirsiniz: https://github.com/cowtowncoder/java-uuid-generator


Sizin durumunuz için UUID.randomUUID (). ToString () ile ilgili sorun nedir? Ayrıca (teorik olarak) statik bir final SecureRandom tutarak (onu uçucu hale getirerek) entropiyi azalttığınızı unutmayın. Ayrıca neden generaUniqueId eşitlemek? Bu, tüm iş parçacıklarınızın bu yöntemde engellendiği anlamına gelir.
Maxim Veksler

Her şeyden önce Safehaus, JUG'un daha hızlı olduğunu iddia ediyor. Ayrıca, ihtiyaç duymayabileceğiniz makineler arasında benzersiz kimlikler oluşturabilir. Tüm yöntemler arasında en şişman olan zamana dayalı bir yöntemi vardır. Evet, burada senkronize gerekli değildir çünkü 'SecureRandom'un zaten iş parçacığı güvenli olduğunu fark ettim. SecureRandom'da statik finalin bildirilmesi entropiyi neden azaltsın ki? Merak ediyorum :) Daha fazla detay burada: jug.safehaus.org/FAQ
Sheng Chien

JUG, rasgele sayı tabanlı UUID'ler de oluşturabilir; ancak geliştiricilerin zamana dayalı varyantı kullanmayı tercih etmelerinin temel nedenleri ya 10-20x daha hızlı olmasıdır ( cowtowncoder.com/blog/archives/2010/10/entry_429.html ); ya da benzersiz kimlikleri (bu biraz komik) üretmek için rasgeleliğe güvenmiyorlar
StaxMan

jug.safehaus.org artık mevcut değil, ancak SSS bölümünü raw.github.com/cowtowncoder/java-uuid-generator/3.0/…
21

JUG'dan bahsettiğim için +1 - Yararlılığını gözden geçirdim, ancak bazı ciddi java.util.UUIDalternatifler olduğunu bilmek güzel .
Greg Dubicki

8

Basit bir çözüm

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

(Varolan çözümler gibi, yalnızca String # replaceAll çağrısından kaçınır . Burada düzenli ifade değiştirme gerekli değildir, bu nedenle String # replace daha doğal hissettirir, ancak teknik olarak yine de düzenli ifadelerle uygulanır. UUID oluşturma yedek parçadan daha pahalıysa, çalışma zamanında önemli bir fark olmamalıdır.)

UUID sınıfını kullanmak çoğu senaryo için muhtemelen yeterince hızlıdır, ancak postprocessing gerektirmeyen bazı özel elle yazılmış varyantların daha hızlı olmasını beklerim. Her neyse, genel hesaplamanın darboğazı normalde rastgele sayı üreteci olacaktır. UUID sınıfı durumunda SecureRandom kullanır .

Hangi rasgele sayı üretecinin kullanılacağı da uygulamaya bağlı bir değiş tokuştur. Güvenlik açısından duyarlıysa, SecureRandom genel olarak tavsiye niteliğindedir. Aksi takdirde, ThreadLocalRandom bir alternatiftir (SecureRandom veya eski Rastgele'den daha hızlıdır , ancak şifreleme açısından güvenli değildir).


7

UUID fikirlerin yerini bu kadar çok dize görmek hayran kaldım. Buna ne dersin:

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

UUID'nin tüm toString () yöntemi, ayrıştırılması ve yürütülmesi gereken normal ifadeden veya boş dizeyle değiştirilmekten bahsetmemek için daha pahalı olduğu için bunu yapmanın oruçlu bir yoludur.


6
Bu güvenilir değil. Baştaki bitler 0 ise çıktı daha kısa olacaktır.
OG Dude

7
String.format("0x%016x%016x", f.getMostSignificantBits(), f.getLeastSignificantBits())
Gal

@galets Sorunu çözmek için önde gelen 0'larla ilgili yorumunuzu oyladım, ancak bunun tire kullanımı yerine alternatifine kıyasla daha iyi olup olmayacağını merak ediyorum replace.
igorcadelima


3

Ben sadece UUID toString () yöntemini kopyaladık ve sadece "-" ondan kaldırmak için güncelledi. Diğer tüm çözümlerden çok daha hızlı ve hızlı olacaktır

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);
}

Kullanımı:

generateUUIDString(UUID.randomUUID())

Yansıma kullanan başka bir uygulama

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));

}


0

Ben sadece tire veya tire olmadan UUID'ler oluşturan bu yardımcı programı sınıfı uyguladı . Kullanmak ve paylaşmak serbest düştü. Umarım yardımcı olur!

package your.package.name;

import java.security.SecureRandom;
import java.util.Random;

/**
 * Utility class that creates random-based UUIDs.
 * 
 */
public abstract class RandomUuidStringCreator {

    private static final int RANDOM_VERSION = 4;

    /**
     * Returns a random-based UUID as String.
     * 
     * It uses a thread local {@link SecureRandom}.
     * 
     * @return a random-based UUID string
     */
    public static String getRandomUuid() {
        return getRandomUuid(SecureRandomLazyHolder.SECURE_RANDOM);
    }

    /**
     * Returns a random-based UUID as String WITH dashes.
     * 
     * It uses a thread local {@link SecureRandom}.
     * 
     * @return a random-based UUID string
     */
    public static String getRandomUuidWithDashes() {
        return format(getRandomUuid());
    }

    /**
     * Returns a random-based UUID String.
     * 
     * It uses any instance of {@link Random}.
     * 
     * @return a random-based UUID string
     */
    public static String getRandomUuid(Random random) {

        long msb = 0;
        long lsb = 0;

        // (3) set all bit randomly
        if (random instanceof SecureRandom) {
            // Faster for instances of SecureRandom
            final byte[] bytes = new byte[16];
            random.nextBytes(bytes);
            msb = toNumber(bytes, 0, 8); // first 8 bytes for MSB
            lsb = toNumber(bytes, 8, 16); // last 8 bytes for LSB
        } else {
            msb = random.nextLong(); // first 8 bytes for MSB
            lsb = random.nextLong(); // last 8 bytes for LSB
        }

        // Apply version and variant bits (required for RFC-4122 compliance)
        msb = (msb & 0xffffffffffff0fffL) | (RANDOM_VERSION & 0x0f) << 12; // apply version bits
        lsb = (lsb & 0x3fffffffffffffffL) | 0x8000000000000000L; // apply variant bits

        // Convert MSB and LSB to hexadecimal
        String msbHex = zerofill(Long.toHexString(msb), 16);
        String lsbHex = zerofill(Long.toHexString(lsb), 16);

        // Return the UUID
        return msbHex + lsbHex;
    }

    /**
     * Returns a random-based UUID as String WITH dashes.
     * 
     * It uses a thread local {@link SecureRandom}.
     * 
     * @return a random-based UUID string
     */
    public static String getRandomUuidWithDashes(Random random) {
        return format(getRandomUuid(random));
    }

    private static long toNumber(final byte[] bytes, final int start, final int length) {
        long result = 0;
        for (int i = start; i < length; i++) {
            result = (result << 8) | (bytes[i] & 0xff);
        }
        return result;
    }

    private static String zerofill(String string, int length) {
        return new String(lpad(string.toCharArray(), length, '0'));
    }

    private static char[] lpad(char[] chars, int length, char fill) {

        int delta = 0;
        int limit = 0;

        if (length > chars.length) {
            delta = length - chars.length;
            limit = length;
        } else {
            delta = 0;
            limit = chars.length;
        }

        char[] output = new char[chars.length + delta];
        for (int i = 0; i < limit; i++) {
            if (i < delta) {
                output[i] = fill;
            } else {
                output[i] = chars[i - delta];
            }
        }
        return output;
    }

    private static String format(String string) {
        char[] input = string.toCharArray();
        char[] output = new char[36];

        System.arraycopy(input, 0, output, 0, 8);
        System.arraycopy(input, 8, output, 9, 4);
        System.arraycopy(input, 12, output, 14, 4);
        System.arraycopy(input, 16, output, 19, 4);
        System.arraycopy(input, 20, output, 24, 12);

        output[8] = '-';
        output[13] = '-';
        output[18] = '-';
        output[23] = '-';

        return new String(output);
    }

    // Holds lazy secure random
    private static class SecureRandomLazyHolder {
        static final Random SECURE_RANDOM = new SecureRandom();
    }

    /**
     * For tests!
     */
    public static void main(String[] args) {

        System.out.println("// Using `java.security.SecureRandom` (DEFAULT)");
        System.out.println("RandomUuidCreator.getRandomUuid()");
        System.out.println();
        for (int i = 0; i < 5; i++) {
            System.out.println(RandomUuidStringCreator.getRandomUuid());
        }

        System.out.println();
        System.out.println("// Using `java.util.Random` (FASTER)");
        System.out.println("RandomUuidCreator.getRandomUuid(new Random())");
        System.out.println();
        Random random = new Random();
        for (int i = 0; i < 5; i++) {
            System.out.println(RandomUuidStringCreator.getRandomUuid(random));
        }
    }
}

Bu çıktı:

// Using `java.security.SecureRandom` (DEFAULT)
RandomUuidStringCreator.getRandomUuid()

'f553ca75657b4b5d85bedf1082785a0b'
'525ecc389e934f209b97d0f0db09d9c6'
'93ec6425bb04499ab47b790fd013ab0d'
'c2d438c620ea4cd5baafd448f9fe945b'
'fb4bc5734931415e94e78da62cb5fe0d'

// Using `java.util.Random` (FASTER)
RandomUuidStringCreator.getRandomUuid(new Random())

'051360b5c92d40fbbb89b40842adbacc'
'a993896538aa43faacbcfd83f913f38b'
'720684d22c584d5299cb03cdbc1912d2'
'82cf94ea296a4a138a92825a0068d4a1'
'a7eda46a215c4e55be3aa957ba74ca9c'
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.