Phương pháp hiệu quả để tạo Chuỗi UUID trong JAVA (UUID.randomUUID (). ToString () mà không có dấu gạch ngang)


154

Tôi muốn một tiện ích hiệu quả để tạo ra các chuỗi byte duy nhất. UUID là một ứng cử viên tốt nhưng UUID.randomUUID().toString()tạo ra những thứ như thế 44e128a5-ac7a-4c9a-be4c-224b6bf81b20là tốt, nhưng tôi thích chuỗi không có dấu gạch ngang.

Tôi đang tìm kiếm một cách hiệu quả để tạo ra một chuỗi ngẫu nhiên, chỉ từ các ký tự chữ và số (không có dấu gạch ngang hoặc bất kỳ ký hiệu đặc biệt nào khác).


38
Tại sao các dấu gạch ngang cần phải được loại bỏ để một UUID như vậy được truyền qua HTTP?
Bruno

6
Tôi không nghĩ rằng dấu gạch ngang cần phải được loại bỏ trong HTTP nói chung ... bit nào đang gây rắc rối cho bạn?
Jon Skeet

2
Có thể trong môi trường di động, nếu bạn vẫn trả tiền cho mỗi byte được truyền và sử dụng mạng băng thông thấp và độ trễ cao, việc tiết kiệm 4 byte vẫn rất quan trọng trong một số trường hợp ...
Guido

2
Tôi muốn xóa dấu gạch ngang vì sau này chúng tôi sử dụng chuỗi UUID làm định danh yêu cầu duy nhất, sẽ dễ dàng hơn nhiều khi chỉ sử dụng ký tự thập phân hex sau đó [a-f0-9-].
Maxim Veksler

Tôi đã xóa phần HTTP vì nó không liên quan (như Maxim giải thích), chỉ khiến độc giả nhầm lẫn (như có thể thấy cả trong bình luận và câu trả lời).
Ondra ižka

Câu trả lời:


274

Cái này làm được

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

Ví dụ, Mongodb không sử dụng dấu gạch ngang trong ObjectID. Vì vậy, loại bỏ dấu gạch ngang có thể hữu ích cho api.
Alexey Ryazhskikh 28/03/2015

1
Tôi sẽ cho bạn một lý do tại sao. Có một API tôi đang làm việc với (cấu hình cao, nổi tiếng) không cho phép dấu gạch ngang trong UUID của nó. Bạn phải lột chúng ra.
Michael Gaines

19
Không cần phải thay thế All, sử dụng các biểu thức thông thường. Chỉ cần làm .replace ("-", "")
Craigo

1
Phương thức thay thế của lớp String hơi chậm, tôi nghĩ vậy
bmscomp

@bmscomp cho lần gọi đầu tiên, nó chậm, nhưng đối với lần gọi tiếp theo, không có vấn đề gì.
gaurav

30

Dấu gạch ngang không cần phải được xóa khỏi yêu cầu HTTP như bạn có thể thấy trong URL của chuỗi này. Nhưng nếu bạn muốn chuẩn bị URL được định dạng tốt mà không phụ thuộc vào dữ liệu, bạn nên sử dụng URLEncoder.encode (Chuỗi dữ liệu, Mã hóa chuỗi) thay vì thay đổi dạng dữ liệu chuẩn của bạn. Đối với dấu gạch ngang đại diện chuỗi UUID là bình thường.


"Dấu gạch ngang không cần phải được xóa khỏi yêu cầu HTTP như bạn có thể thấy trong URL của chuỗi này." Không hiểu, trừ khi Stack Overflow sử dụng UUID trước đó trong URL của họ?
RenniePet

1
Không phải url là UUID, mà là dấu gạch ngang:http://stackoverflow.com/questions/3804591/efficient-method-to-generate-uuid-string-in-java-uuid-randomuuid-tostring-w?rq=1
Octavia Togami

12

Cuối cùng tôi đã viết một cái gì đó của riêng tôi dựa trên việc triển khai UUID.java. Lưu ý rằng tôi không tạo UUID , thay vào đó chỉ là chuỗi hex 32 byte ngẫu nhiên theo cách hiệu quả nhất mà tôi có thể nghĩ ra.

Thực hiện

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

Sử dụng

RandomUtil.unique()

Xét nghiệm

Một số đầu vào tôi đã thử nghiệm để đảm bảo nó hoạt động:

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
không chắc chắn tại sao điều này được nâng cấp nhiều hơn, UUID này được tạo mà không có "-" trong phương thức hiệu quả nhất từ ​​tất cả các tùy chọn được viết ở đây. Thay thế chuỗi không tốt hơn sau đó chuyển đổi từ chuỗi dài sang chuỗi. Đúng là cả hai đều là O (n), nhưng ở quy mô mà bạn tạo ra hàng triệu uuid thì một phút nó trở nên có ý nghĩa.
Maxim Veksler

10

Tôi đã sử dụng JUG (Java UUID Generator) để tạo ID duy nhất. Nó là duy nhất trên các JVM. Khá tốt để sử dụng. Đây là mã để bạn tham khảo:

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

Bạn có thể tải xuống thư viện từ: https://github.com/cowtowncoder/java-uuid-generator


Đối với trường hợp của bạn, điều gì sai với UUID.randomUUID (). ToString ()? Cũng lưu ý rằng bạn (về mặt lý thuyết) giảm entropy bằng cách giữ một SecureRandom cuối cùng tĩnh (làm cho nó biến động). còn tại sao đồng bộ hóa GenerUniqueId? Điều này có nghĩa là tất cả các chủ đề của bạn bị chặn trên phương pháp này.
Maxim Veksler

Trước hết, Safehaus tuyên bố JUG nhanh hơn. Và nó có thể tạo ID duy nhất trên các máy mà bạn có thể không cần. Họ có phương pháp dựa trên thời gian là phương pháp béo nhất trong số tất cả các phương pháp. Có, không cần đồng bộ hóa ở đây vì 'Tôi nhận ra SecureRandom đã an toàn cho chủ đề. Tại sao việc khai báo tĩnh cuối cùng trên SecureRandom sẽ làm giảm entropy? Tôi tò mò :) Có nhiều chi tiết hơn ở đây: jug.safehaus.org/FAQ
Sheng Chiến

JUG cũng có thể tạo UUID dựa trên số ngẫu nhiên; nhưng lý do chính khiến các nhà phát triển thích sử dụng biến thể dựa trên thời gian là vì nó nhanh hơn 10-20 lần ( cowtowncoder.com/blog/archives/2010/10/entry_429.html ); hoặc rằng họ không tin tưởng vào sự ngẫu nhiên để tạo ra các id duy nhất (điều này hơi buồn cười)
StaxMan

jug.safehaus.org không còn tồn tại nữa, nhưng bạn có thể tìm thấy Câu hỏi thường gặp tại raw.github.com/cowtowncoder/java-uuid-generator/3.0/ lỗi
Daniel Serodio

+1 để đề cập đến JUG - Tôi đã xem xét tính hữu dụng của nó nhưng thật tốt khi biết rằng có một số nghiêm trọng java.util.UUID lựa chọn thay thế .
Greg Dubicki

8

Một giải pháp đơn giản là

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

(Giống như các giải pháp hiện có, chỉ có nó mới tránh được cuộc gọi Chuỗi # thay thế. Cuộc gọi thay thế biểu thức thông thường không bắt buộc ở đây, vì vậy Chuỗi # thay thế cảm thấy tự nhiên hơn, mặc dù về mặt kỹ thuật, nó vẫn được triển khai với các biểu thức chính quy. Cho rằng việc tạo UUID là tốn kém hơn so với thay thế, không nên có sự khác biệt đáng kể trong thời gian chạy.)

Sử dụng lớp UUID có thể đủ nhanh cho hầu hết các kịch bản, mặc dù tôi mong đợi rằng một số biến thể viết tay chuyên dụng, không cần xử lý hậu kỳ, sẽ nhanh hơn. Dù sao, nút cổ chai của tính toán tổng thể thường sẽ là trình tạo số ngẫu nhiên. Trong trường hợp của lớp UUID, nó sử dụng SecureRandom .

Bộ tạo số ngẫu nhiên nào sẽ sử dụng cũng là một sự đánh đổi phụ thuộc vào ứng dụng. Nếu nó nhạy cảm với bảo mật, nói chung, SecureRandom là khuyến nghị. Mặt khác, ThreadLocalRandom là một giải pháp thay thế (nhanh hơn SecureRandom hoặc cũ Random , nhưng không bảo mật bằng mật mã).


7

Tôi ngạc nhiên khi thấy rất nhiều chuỗi thay thế ý tưởng của UUID. Còn cái này thì sao:

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

Đây là cách thực hiện nhanh vì toàn bộ toString () của UUID đã đắt hơn chưa kể đến biểu thức thông thường phải được phân tích cú pháp và thực thi hoặc thay thế bằng chuỗi rỗng.


6
Điều này không đáng tin cậy. Đầu ra sẽ ngắn hơn nếu các bit hàng đầu là 0.
OG Dude

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

@galets Mặc dù tôi đã bình chọn bình luận của bạn để giải quyết vấn đề với số 0 hàng đầu, tôi tự hỏi liệu điều này có tốt hơn so với phương án thay thế dấu gạch ngang bằng cách sử dụng không replace.
igorcadelima


3

Tôi vừa sao chép phương thức UUID toString () và vừa cập nhật để xóa "-" khỏi nó. Nó sẽ nhanh hơn và thẳng hơn bất kỳ giải pháp nào khác

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

Sử dụng:

generateUUIDString(UUID.randomUUID())

Một cách thực hiện khác bằng phản xạ

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

}

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.