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.