JAVA에서 UUID 문자열을 생성하는 효율적인 방법 (대시없이 UUID.randomUUID (). toString ())


154

고유 한 바이트 시퀀스를 생성하는 효율적인 유틸리티를 원합니다. UUID는 좋은 후보이지만 좋은 것을 UUID.randomUUID().toString()생성 44e128a5-ac7a-4c9a-be4c-224b6bf81b20하지만 대시가없는 문자열을 선호합니다.

영숫자 문자 (대시 또는 다른 특수 기호 없음)에서만 무작위 문자열을 생성하는 효율적인 방법을 찾고 있습니다.


38
HTTP를 통해 UUID를 전송하려면 대시를 제거해야하는 이유는 무엇입니까?
— Bruno

6
나는 일반적으로 HTTP에서 대시를 제거해야한다고 생각하지 않았습니다 ... 어떤 비트가 번거 롭습니까?
— Jon Skeet

2
아마도 모바일 환경에서, 전송 된 각 바이트에 대해 지불하고 저 대역폭 및 높은 지연 시간 네트워크를 사용하는 경우 일부 시나리오에서 4 바이트를 절약하는 것이 여전히 중요합니다.
— Guido

2
나중에 UUID 문자열을 고유 한 요청 식별자로 사용하기 때문에 대시를 제거하고 싶습니다. 16 진 10 진수 문자 ([a-f0-9-]) 만 사용하는 것이 훨씬 쉽습니다.
— Maxim Veksler

HTTP 부분은 관련이 없기 때문에 제거했습니다 (Maxim이 설명했듯이). 독자를 혼란스럽게합니다 (댓글과 답변 모두에서 볼 수 있음)
— 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 2016 년

1
이유를 알려 드리겠습니다. UUID에서 대시를 허용하지 않는 API (높은 프로파일, 잘 알려진)로 작업하고 있습니다. 당신은 그들을 제거해야합니다.
— Michael Gaines

19
정규식을 사용하는 replaceAll을 수행 할 필요가 없습니다.
— .replace

1
String 클래스의 대체 방법은 내가 생각하는, 조금 느린입니다
— bmscomp

첫 번째 호출의 경우 @bmscomp는 느리지 만 다음 호출의 경우 문제가 없습니다.
— gaurav

30

이 스레드의 URL에서 볼 수 있듯이 대시는 HTTP 요청에서 제거 할 필요가 없습니다. 그러나 데이터에 의존하지 않고 올바른 형식의 URL을 준비하려면 표준 데이터 형식을 변경하는 대신 URLEncoder.encode (String data, String encoding)를 사용해야합니다. UUID 문자열 표현의 경우 대시는 정상입니다.


"이 스레드의 URL에서 볼 수 있듯이 대시는 HTTP 요청에서 제거 할 필요가 없습니다." 이전에 스택 오버플로에서 URL에 UUID를 사용한 경우를 제외하고
— RenniePet

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

우선 Safehaus는 JUG가 더 빠르다고 주장합니다. 또한 필요하지 않은 여러 시스템에서 고유 한 ID를 생성 할 수 있습니다. 그들은 모든 방법 중에서 가장 치명적인 시간 기반 방법을 가지고 있습니다. 예, 여기서 동기화 할 필요가 없습니다. 'SecureRandom이 이미 스레드 안전하다는 것을 깨달았습니다. SecureRandom에서 정적 최종을 선언하면 엔트로피가 감소하는 이유는 무엇입니까? 궁금합니다 :) 여기에 더 자세한 내용이 있습니다 : 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 Dude

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

@galets 선행 0으로 문제를 해결하는 것에 대한 귀하의 의견을 표명했지만,을 사용하여 대시를 대체하는 대안과 비교하여 더 나은지 궁금합니다 replace.
— igorcadelima


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

}

2

org.apache.commons.codec.binary.Base64를 사용하여 UUID를 길이가 22 자이고 UUID와 동일한 고유성을 갖는 URL 안전 고유 문자열로 변환합니다.

UUID 저장에 코드를 base64 문자열로 게시했습니다.


0

방금 대시가 있거나없는 UUID를 String으로 만드는이 유틸리티 클래스를 구현했습니다 . 자유롭게 사용하고 공유하십시오. 도움이 되길 바랍니다.

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

이것은 출력입니다.

// 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'
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.