Эффективный метод для генерации строки UUID в JAVA (UUID.randomUUID (). ToString () без черточек)

Я хотел бы эффективную утилиту для генерации уникальных последовательностей байтов. UUID хороший кандидат, ноUUID.randomUUID().toString() генерирует такие вещи, как44e128a5-ac7a-4c9a-be4c-224b6bf81b20 это хорошо, если вам не нужно передавать его по HTTP, и в этом случае дефисы должны быть удалены.

Я ищу эффективный способ генерировать случайные строки, только из буквенно-цифровых символов (без черточек или любых других специальных символов).

 Bruno27 сент. 2010 г., 16:08
Почему необходимо удалить тире, чтобы такой UUID передавался по HTTP?
 Guido27 сент. 2010 г., 16:36
Возможно, в мобильной среде, если вы по-прежнему платите за каждый передаваемый байт и используете сеть с низкой пропускной способностью и высокой задержкой, сохранение 4 байт все еще важно в некоторых сценариях ...
 Jon Skeet27 сент. 2010 г., 16:08
Я не думал, что черты должны быть удалены в HTTP вообще ... какой бит вызывает у вас беспокойство?
 Maxim Veksler28 сент. 2010 г., 12:19
Я хочу, чтобы тире были удалены, потому что мы позже используем строку UUID в качестве уникального идентификатора запроса, гораздо проще работать только с шестнадцатеричными десятичными символами, чем [a-f0-9-].

Ответы на вопрос(8)

Решение Вопроса

Закончил писать что-то свое на основе реализации UUID.java. Обратите внимание, что яне генерирует UUIDвместо этого просто случайная 32-байтовая шестнадцатеричная строка наиболее эффективным способом, который я мог придумать.

Реализация
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));
}
 Maxim Veksler08 сент. 2016 г., 14:48
не уверен, почему за это проголосовали больше, это сгенерировало UUID без "-" в самом эффективном методе из всех опций, написанных здесь. Замена строки не лучше, чем преобразование из длинной в строку. Это правда, что оба являются O (n), но в масштабе, где вы генерируете миллионы единиц в минуту, это становится значимым.

Я поражен, увидев, что так много строк заменяет идеи UUID. Как насчет этого:

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

Это быстрый способ сделать это, поскольку весь метод toString () UUID уже стоит дороже, не говоря уже о регулярном выражении, которое нужно проанализировать и выполнить, или о замене пустой строкой.

 galets21 сент. 2016 г., 02:17
String.format("0x%016x%016x", f.getMostSignificantBits(), f.getLeastSignificantBits())
 OG Dude09 авг. 2016 г., 19:55
Это не надежно. Вывод будет короче, если начальные биты равны 0.
 Mykhaylo Adamovych19 июн. 2019 г., 17:11
 igorcadelima25 авг. 2017 г., 08:25
@galets Хотя я и проголосовал за ваш комментарий за решение проблемы с ведущими нулями, мне интересно, будет ли это лучше, чем альтернатива замены тире с помощьюreplace.

Я только что скопировал метод toString () UUID и просто обновил его, чтобы удалить из него «-». Это будет намного быстрее и понятнее, чем любое другое решение.

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

}

Я использовал JUG (Java UUID Generator) для генерации уникального идентификатора. Это уникально среди 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

 StaxMan24 окт. 2010 г., 05:30
JUG также может генерировать UUID на основе случайных чисел; но главная причина, по которой разработчики предпочитают использовать вариант, основанный на времени, заключается либо в том, что он в 10-20 раз быстрее (cowtowncoder.com/blog/archives/2010/10/entry_429.html); или что они не доверяют случайности для создания уникальных идентификаторов (что довольно забавно)
 Daniel Serodio20 сент. 2012 г., 23:58
jug.safehaus.org больше не существует, но вы можете найти FAQ наraw.github.com/cowtowncoder/java-uuid-generator/3.0/...
 Sheng Chien28 сент. 2010 г., 16:46
Прежде всего, Safehaus утверждает, что JUG быстрее. И он может генерировать уникальные идентификаторы на разных машинах, которые вам могут не понадобиться. У них есть метод, основанный на времени, который является лучшим из всех методов. Да, синхронизировать здесь не нужно, потому что я понял, что SecureRandom уже поточно-ориентирован. Почему объявление статического финала на SecureRandom уменьшило бы энтропию? Мне любопытно :) Есть более подробная информация здесь:jug.safehaus.org/FAQ
 Greg Dubicki06 сент. 2015 г., 19:28
+1 за упоминание JUG - я рассмотрел его полезность, но приятно знать, что есть серьезныеjava.util.UUID альтернативы.
 Maxim Veksler28 сент. 2010 г., 12:27
Для вашего случая, что не так с UUID.randomUUID (). ToString ()? Также обратите внимание, что вы (теоретически) уменьшаете энтропию, удерживая статический окончательный SecureRandom (делая его изменчивым). и зачем синхронизировать generateUniqueId? Это означает, что все ваши темы заблокированы по этому методу.

Это делает это:

public static void main(String[] args) {
    final String uuid = UUID.randomUUID().toString().replace("-", "");
    System.out.println("uuid = " + uuid);
}
 Craigo31 мая 2016 г., 10:50
Не нужно делать replaceAll, который использует регулярные выражения. Просто сделайте .replace ("-", "")
 gaurav28 февр. 2019 г., 13:38
работает безупречно Стив!
 Alexey Ryazhskikh28 мар. 2015 г., 14:28
Например, Mongodb не использует тире в ObjectID. Таким образом, удаление штрихов может быть полезным для API.
 bmscomp20 авг. 2019 г., 17:22
Я думаю, что метод замены класса String немного медленный
 Michael Gaines28 окт. 2015 г., 04:28
Я дам вам причину почему. Есть API, с которым я работаю (широко известный, хорошо известный), который не допускает тире в его UUID. Вы должны раздеть их.
 gaurav28 авг. 2019 г., 10:57
@bmscomp для первого вызова, это медленно, но для следующих вызовов нет проблем.

Черточки не нужно удалять из HTTP-запроса, как вы можете видеть в URL этой темы. Но если вы хотите подготовить правильно сформированный URL без зависимости от данных, вы должны использовать URLEncoder.encode (String data, String encoding) вместо изменения стандартной формы ваших данных. Для строкового представления UUID штрихи нормальны.

 Octavia Togami22 нояб. 2014 г., 06:52
Не то, что URL-адрес является UUID, но он имеет тире:http://stackoverflow.com/questions/3804591/efficient-method-to-generate-uuid-string-in-java-uuid-randomuuid-tostring-w?rq=1
 RenniePet17 сент. 2014 г., 15:17
«Черточки не нужно удалять из HTTP-запроса, как вы можете видеть в URL этой темы». Не понимаю, разве Stack Overflow ранее использовал UUID в своих URL?

Я использую org.apache.commons.codec.binary.Base64, чтобы преобразовать UUID в уникальную строку, безопасную для URL, длиной 22 символа и обладающую той же уникальностью, что и UUID.

Я разместил свой код наХранение UUID как строки base64

Простое решение

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

(Как и существующие решения, только то, что он избегаетСтрока # replaceAll вызов. Замена регулярных выражений здесь не требуется, поэтомуСтрока # заменить кажется более естественным, хотя технически это все еще реализовано с помощью регулярных выражений. Учитывая, что генерация UUID обходится дороже, чем замена, не должно быть существенной разницы во времени выполнения.)

Использование класса UUID, вероятно, достаточно быстро для большинства сценариев, хотя я ожидаю, что какой-то специализированный рукописный вариант, который не требует постобработки, будет быстрее. В любом случае, узким местом всех вычислений обычно является генератор случайных чисел. В случае класса UUID он используетSecureRandom.

Какой генератор случайных чисел использовать, также является компромиссом, который зависит от приложения. Если это чувствительно к безопасности, SecureRandom, как правило, является рекомендацией. Иначе,ThreadLocalRandom это альтернатива (быстрее, чем SecureRandom или старыйслучайный, но не криптографически безопасный).

Ваш ответ на вопрос