Попытка назначить случайный идентификатор объекту [дубликат]

Исключение нулевого указателя генерируется, когда приложение пытается использовать null в случае, когда требуется объект. К ним относятся:

  1. Вызов метода экземпляра объекта null.
  2. Доступ или изменение поля объекта null.
  3. Принимая длину null, как если бы это был массив.
  4. Доступ или изменение слотов null, как если бы это был массив.
  5. Бросок null как будто это было значение Throwable.

Приложения должны бросать экземпляры этого класса, чтобы указать на другие незаконные использования объекта null.

Ссылка: http://docs.oracle.com/javase/8/docs/api/java/lang/NullPointerException.html

1502
задан 7 revs, 5 users 50% 8 December 2014 в 02:51
поделиться

30 ответов

Алгоритм

Чтобы сгенерировать случайную строку, объедините символы, произвольно выбранные из набора допустимых символов, пока строка не достигнет желаемой длины.

Реализация

Вот несколько довольно простой и очень гибкий код для генерации случайных идентификаторов. Прочитайте следующую информацию для важных примечаний к применению.

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

public class RandomString {

    /**
     * Generate a random string.
     */
    public String nextString() {
        for (int idx = 0; idx < buf.length; ++idx)
            buf[idx] = symbols[random.nextInt(symbols.length)];
        return new String(buf);
    }

    public static final String upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

    public static final String lower = upper.toLowerCase(Locale.ROOT);

    public static final String digits = "0123456789";

    public static final String alphanum = upper + lower + digits;

    private final Random random;

    private final char[] symbols;

    private final char[] buf;

    public RandomString(int length, Random random, String symbols) {
        if (length < 1) throw new IllegalArgumentException();
        if (symbols.length() < 2) throw new IllegalArgumentException();
        this.random = Objects.requireNonNull(random);
        this.symbols = symbols.toCharArray();
        this.buf = new char[length];
    }

    /**
     * Create an alphanumeric string generator.
     */
    public RandomString(int length, Random random) {
        this(length, random, alphanum);
    }

    /**
     * Create an alphanumeric strings from a secure generator.
     */
    public RandomString(int length) {
        this(length, new SecureRandom());
    }

    /**
     * Create session identifiers.
     */
    public RandomString() {
        this(21);
    }

}

Примеры использования

Создайте ненадежный генератор для 8-символьных идентификаторов:

RandomString gen = new RandomString(8, ThreadLocalRandom.current());

Создайте защищенный генератор для идентификаторов сеанса:

RandomString session = new RandomString();

Создайте генератор с легко читаемыми кодами для печати. Строки длиннее, чем полные буквенно-цифровые строки, чтобы компенсировать использование меньшего количества символов:

String easy = RandomString.digits + "ACEFGHJKLMNPQRUVWXYabcdefhijkprstuvwx";
RandomString tickets = new RandomString(23, new SecureRandom(), easy);

Использовать в качестве идентификаторов сеанса

Генерация идентификаторов сеансов, которые могут быть уникальными, недостаточно хороша, или вы можете просто использовать простой счетчик. Атакующие захватывают сессии, когда используются предсказуемые идентификаторы.

Существует напряженность между длиной и безопасностью. Более короткие идентификаторы легче угадать, потому что возможностей меньше. Но более длинные идентификаторы потребляют больше памяти и пропускной способности. Больший набор символов помогает, но может вызвать проблемы с кодированием, если идентификаторы включены в URL-адреса или повторно введены вручную.

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

Использовать в качестве идентификаторов объекта

Не для каждого приложения требуется безопасность. Случайное назначение может быть эффективным способом для нескольких объектов генерировать идентификаторы в общем пространстве без какой-либо координации или разделения.

Идентификаторы, созданные без принятия мер, чтобы сделать их непредсказуемыми должны быть защищены другими средствами, если злоумышленник может просматривать и манипулировать ими, как это происходит в большинстве веб-приложений. Должна быть отдельная система авторизации, которая защищает объекты, чей идентификатор может быть догадан злоумышленником без разрешения доступа.

Следует также проявлять осторожность, чтобы использовать идентификаторы, которые достаточно длинны, чтобы сделать конфликты маловероятными с учетом ожидаемого общего количества количество идентификаторов. Это называется «парадоксальным днем ​​рождения». Вероятность столкновения p равна приблизительно n2 / (2qx), где n - количество фактически генерируемых идентификаторов, q - количество различных символов в алфавите, а x - длина идентификаторов. Это должно быть очень маленькое число, например, 2-50 или меньше.

Это показывает, что вероятность столкновения между 500-кратным 15-символьным идентификатором составляет около 2-52, что, вероятно, менее вероятно, чем необнаруженное ошибки из космических лучей и т. д.

Сравнение с UUIDs

Согласно их спецификации, UUID не предназначены для непредсказуемости, а не должны использоваться как идентификаторы сеанса.

UUID в их стандартном формате занимают много места: 36 символов только для 122 бит энтропии. (Не все биты «случайного» UUID выбираются случайным образом.) Случайно выбранная буквенно-цифровая строка содержит большую энтропию всего лишь 21 символ.

UUID не являются гибкими; они имеют стандартизованную структуру и макет. Это их главная добродетель, а также их главная слабость. При сотрудничестве с сторонней стороной стандартизация, предлагаемая UUID, может оказаться полезной. Для чисто внутреннего использования они могут быть неэффективными.

1401
ответ дан 16 revs, 7 users 77% 19 August 2018 в 09:45
поделиться
  • 1
    Если вам нужны пробелы, вы можете нажать на .replaceAll("\\d", " "); в конце строки return new BigInteger(130, random).toString(32);, чтобы выполнить обмен регулярными выражениями. Он заменяет все цифры пробелами. Отлично работает для меня: я использую это как замену интерфейсного Lorem Ipsum – weisjohn 7 October 2011 в 16:00
  • 2
    @weisjohn Это хорошая идея. Вы можете сделать что-то подобное со вторым методом, удалив цифры из symbols и используя пробел; вы можете управлять средним словом " путем изменения количества пробелов в символах (больше случаев для более коротких слов). Для действительно передового поддельного текстового решения вы можете использовать цепь Маркова! – erickson 7 October 2011 в 17:02
  • 3
    Я пробовал это, но иногда это всего лишь 31 длинный. – Daniel Szalay 20 December 2011 в 01:46
  • 4
    Почему .toString (32), а не .toString (36)? – ejain 21 February 2012 в 21:13
  • 5
    @ejain, потому что 32 = 2 ^ 5; каждый символ будет представлять ровно 5 бит, а 130 бит могут быть равномерно разделены на символы. – erickson 21 February 2012 в 23:38

Если вы счастливы использовать классы Apache, вы можете использовать org.apache.commons.text.RandomStringGenerator (commons-text).

Пример:

RandomStringGenerator randomStringGenerator =
        new RandomStringGenerator.Builder()
                .withinRange('0', 'z')
                .filteredBy(CharacterPredicates.LETTERS, CharacterPredicates.DIGITS)
                .build();
randomStringGenerator.generate(12); // toUpperCase() if you want

Поскольку commons-lang 3.6, RandomStringUtils устарел.

455
ответ дан 10 revs, 9 users 42% 19 August 2018 в 09:45
поделиться
  • 1
    Просто просмотрел упомянутый класс библиотеки Apache Commons Lang 3.3.1 - и он использует только java.util.Random для предоставления случайных последовательностей, поэтому он создает неустойчивые последовательности . – Yura 3 April 2014 в 15:51
  • 2
    Убедитесь, что вы используете SecureRandom при использовании RandomStringUtils: public static java.lang.String random(int count, int start, int end, boolean letters, boolean numbers, @Nullable char[] chars, java.util.Random random) – Ruslans Uralovs 3 March 2015 в 14:28

Это легко достижимо без каких-либо внешних библиотек.

1. Генерация криптографических псевдослучайных данных

Сначала вам нужен криптографический PRNG. Java имеет SecureRandom , для которого обычно используется лучший источник энтропии на машине (например, /dev/random). Подробнее читайте здесь.

SecureRandom rnd = new SecureRandom();
byte[] token = new byte[byteLength];
rnd.nextBytes(token);

Примечание: SecureRandom - самый медленный, но наиболее безопасный способ в Java генерации случайных байтов. Тем не менее, я рекомендую НЕ рассматривать производительность здесь, поскольку она обычно не оказывает реального влияния на ваше приложение, если вам не нужно генерировать миллионы токенов в секунду.

2. Требуемое пространство возможных значений

Затем вам нужно решить, «как уникально» ваш токен. Целая и единственная точка рассмотрения энтропии заключается в том, чтобы убедиться, что система может противостоять атакам с использованием грубой силы: пространство возможных значений должно быть настолько большим, чтобы любой атакующий мог только попробовать незначительную долю значений в непухотное время 1 [/ д2]. Уникальные идентификаторы, такие как случайные UUID , имеют 122 бит энтропии (т. Е. 2 ​​^ 122 = 5.3x10 ^ 36) - вероятность столкновения равна «* (...), чтобы существовала одна в миллиардной вероятности дублирования необходимо создать 103 триллиона версий UUID 2 ". Мы выберем 128 бит, так как он точно соответствует 16 байтам и считается достаточно высоким для того, чтобы быть уникальным для всех, но наиболее экстремальных, используемых случаев, и вам не нужно думать о дубликатах. Вот простая таблица сравнения энтропии, включая простой анализ проблемы рождения .

Для простых требований 8 или 12 длина байта может быть достаточной, но с 16 байтами вы находитесь на «безопасной стороне».

И это в основном это. Последнее стоит подумать о кодировании, чтобы его можно было представить в виде печатного текста (read, a String).

3. Бинарное кодирование текста

Типичные кодировки включают в себя:

  • Base64 каждый символ кодирует 6 бит, создавая 33% служебных данных. К сожалению, стандартная реализация в JDK ( 7 и ниже отсутствует] - в Android и Java 8 + ). Но существует множество библиотек , которые добавляют это. Недостатком является то, что стандарт Base64 небезопасен, например. URL-адреса и имя файла в большинстве файловых систем, требующих дополнительного кодирования (например, url-кодирование ) или URL-адрес безопасной версии Base64 используется . Пример кодирования 16 байтов с заполнением: XfJhfv3C0P6ag7y9VQxSbw==
  • Base32 каждый символ кодирует 5 бит, создавая 40% служебных данных. Это будет использовать A-Z и 2-7, что делает его разумным пространственно эффективным, нечувствительным к регистру буквенно-цифровым. Стандартная реализация в JDK отсутствует. Пример кодирования 16 байтов без заполнения: WUPIL5DQTZGMF4D3NX5L7LNFOY
  • Base16 (шестнадцатеричный) каждый символ кодирует 4 бит, требующий 2 символа на каждый байт (т. Е. 16 байт создает строку длиной 32 ). Поэтому hex меньше пространства, чем Base32, но безопасен для использования в большинстве случаев (url), поскольку он использует только 0-9 и A - F. Пример кодирования 16 байтов: 4fa3dd0f57cb3bf331441ed285b27735. См. обсуждение SO о преобразовании в hex здесь.

Дополнительные кодировки, такие как Base85 и экзотический Base122 существуют с лучшей / меньшей эффективностью пространства. Вы можете создать свою собственную кодировку (которая в основном отвечает большинству ответов в этом потоке), но я бы посоветовал это сделать, если у вас нет особых требований. См. больше схем кодирования в статье Википедии.

4. Сводка и пример

  • Используйте SecureRandom
  • Используйте не менее 16 байт (2 ^ 128) возможных значений
  • Кодируйте в соответствии с вашими требованиями (обычно hex или base32, если вам нужно, чтобы оно было буквенно-цифровым)

Не

  • . .. используйте свою домашнюю кодировку для варки: лучше поддерживаются и читаемы для других, если они видят, какую стандартную кодировку вы используете, а не странно для создания циклов за один раз.
  • ... используйте UUID: вы тратите 6bits энтропии и имеете подробное строковое представление

Пример: Hex Token Generator

public static String generateRandomHexToken(int byteLength) {
    SecureRandom secureRandom = new SecureRandom();
    byte[] token = new byte[byteLength];
    secureRandom.nextBytes(token);
    return new BigInteger(1, token).toString(16); //hex encoding
}

//generateRandomHexToken(16) -> 2189df7475e96aa3982dbeab266497cd

Пример: Инструмент

Если вы хотите готовый к использованию инструмент cli, вы можете использовать кости: https://github.com/patrickfav/dice

32
ответ дан 14 revs 19 August 2018 в 09:45
поделиться
  • 1
    Этот ответ завершен и работает без добавления какой-либо зависимости. Если вы хотите избежать появления минус-знаков на выходе, вы можете предотвратить отрицательный BigInteger s, используя параметр конструктора: BigInteger(1, token) вместо BigInteger(token). – francoisr 11 July 2017 в 07:50
  • 2
    Танки @francoisr для подсказки, я редактировал пример кода – for3st 11 July 2017 в 08:38
  • 3
    – anothermh 4 October 2018 в 01:45

Вы упоминаете «простой», но на всякий случай кто-то ищет что-то, что отвечает более строгим требованиям безопасности, вы можете взглянуть на jpwgen . jpwgen моделируется после pwgen в Unix и очень настраивается.

3
ответ дан 2 revs 19 August 2018 в 09:45
поделиться
  • 1
    Ссылка мертва: github.com/zhelev/jpwgen – for3st 25 June 2017 в 01:27
  • 2
    Спасибо, исправил это. Так что это наименьший источник, и ссылка действительна. С другой стороны, это не похоже, что оно было обновлено через некоторое время, хотя я вижу, что pwgen недавно обновлен. – michaelok 26 June 2017 в 22:50
public static String randomSeriesForThreeCharacter() {
    Random r = new Random();
    String value="";
    char random_Char ;
    for(int i=0; i<10;i++)
    { 
        random_Char = (char) (48 + r.nextInt(74));
        value=value+random_char;
    }
    return value;
}
3
ответ дан 2 revs, 2 users 65% 19 August 2018 в 09:45
поделиться
  • 1
    Эта конкатенация строк излишне неэффективна. И сумасшедший отступ делает ваш код почти нечитаемым. Это то же самое, что и идея Джейми , но плохо выполнена. – erickson 4 October 2013 в 06:36

Вы можете использовать библиотеку Apache для этого: RandomStringUtils

RandomStringUtils.randomAlphanumeric(20).toUpperCase();
88
ответ дан 2 revs, 2 users 91% 19 August 2018 в 09:45
поделиться
  • 1
    @kamil, я посмотрел исходный код для RandomStringUtils, и он использует экземпляр java.util.Random, созданный без аргументов. Документация для java.util.Random говорит, что она использует текущее системное время, если семя не предоставляется. Это означает, что он не может использоваться для идентификаторов / ключей сеанса, так как злоумышленник может легко предсказать, что генерируемые идентификаторы сеанса находятся в данный момент времени. – Inshallah 26 September 2012 в 11:14
  • 2
    @Inshallah: Вы (излишне) перерабатываете систему. Хотя я согласен, что он использует время как семя, злоумышленник должен иметь доступ к следующим данным, чтобы фактически получить то, что он хочет. 1. Время до точной миллисекунды, когда код был посеян 2. Количество вызовов, которые произошли до сих пор 3. Атомичность для его собственного вызова (так что количество звонков - так далеко). Если ваш атакующий имеет все три из этих вещей, тогда у вас гораздо больше проблем ... – Ajeet Ganga 14 October 2013 в 00:36
  • 3
    зависимость градиента: compile 'commons-lang:commons-lang:2.6' – younes0 19 January 2015 в 15:35
  • 4
    @Ajeet это неправда. Вы можете получить состояние генератора случайных чисел с его выхода. Если злоумышленник может генерировать несколько тысяч вызовов для генерации случайных атак API, злоумышленник сможет предсказать все будущие маркеры API. – Thomas Grainger 20 December 2016 в 14:52
  • 5
    @AjeetGanga Ничего общего с инженерством. Если вы хотите создать идентификаторы сеанса, вам нужен криптографический псевдослучайный генератор. Каждый prng, использующий время как семя, предсказуем и очень небезопасен для данных, которые должны быть непредсказуемыми. Просто используйте SecureRandom, и вы хороши. – for3st 19 September 2017 в 10:37

Удивительно, что никто не предложил это, но:

import java.util.UUID

UUID.randomUUID().toString();

Легко.

Преимущество этого в том, что UUID являются хорошими и длинными и гарантированно почти невозможно столкнуться.

Википедия имеет хорошее объяснение:

«... только после генерации 1 миллиарда UUID каждую секунду в течение следующих 100 лет вероятность создания всего одного дубликата будет около 50%».

http: // ru.wikipedia.org/wiki/Universally_unique_identifier#Random_UUID_probability_of_duplicates

Первые 4 бита - это тип версии и 2 для варианта, так что вы получаете 122 бит случайных значений. Поэтому, если вы хотите , вы можете обрезать с конца, чтобы уменьшить размер UUID. Это не рекомендуется, но у вас все еще есть множество случайностей, достаточно для ваших записей 500k.

29
ответ дан 2 revs, 2 users 97% 19 August 2018 в 09:45
поделиться

Возможно, это полезно

package password.generater;

import java.util.Random;

/**
 *
 * @author dell
 */
public class PasswordGenerater {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        int length= 11;
        System.out.println(generatePswd(length));

        // TODO code application logic here
    }
    static char[] generatePswd(int len){
        System.out.println("Your Password ");
        String charsCaps="ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 
        String Chars="abcdefghijklmnopqrstuvwxyz";
        String nums="0123456789";
        String symbols="!@#$%^&*()_+-=.,/';:?><~*/-+";
        String passSymbols=charsCaps + Chars + nums +symbols;
        Random rnd=new Random();
        char[] password=new char[len];

        for(int i=0; i<len;i++){
            password[i]=passSymbols.charAt(rnd.nextInt(passSymbols.length()));
        }
      return password;

    }
}
2
ответ дан 2 revs, 2 users 97%user5138430 19 August 2018 в 09:45
поделиться

Не нравится какой-либо из этих ответов относительно «простого» решения: S

Я бы выбрал простой;), чистый java, один вкладыш (энтропия основана на случайной длине строки и заданный набор символов):

public String randomString(int length, String characterSet) {
    return IntStream.range(0, length).map(i -> new SecureRandom().nextInt(characterSet.length())).mapToObj(randomInt -> characterSet.substring(randomInt, randomInt + 1)).collect(Collectors.joining());
}

@Test
public void buildFiveRandomStrings() {
    for (int q = 0; q < 5; q++) {
        System.out.println(randomString(10, "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"));//charachterSet can basically be anything
    }
}

или (более читаемый старый способ)

public String randomString(int length, String characterSet) {
    StringBuilder sb = new StringBuilder(); //consider using StringBuffer if needed
    for (int i = 0; i < length; i++) {
        int randomInt = new SecureRandom().nextInt(characterSet.length());
        sb.append(characterSet.substring(randomInt, randomInt + 1));
    }
    return sb.toString();
}

@Test
public void buildFiveRandomStrings() {
    for (int q = 0; q < 5; q++) {
        System.out.println(randomString(10, "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")); //charachterSet can basically be anything
    }
}

Но, с другой стороны, вы также можете использовать UUID, который довольно хорош энтропия ( https://en.wikipedia.org/wiki/Universally_unique_identifier#Collisions ):

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

Надеюсь, что это поможет.

8
ответ дан 3 revs 19 August 2018 в 09:45
поделиться

Вот код одной строки от AbacusUtil

String.valueOf(CharStream.random('0', 'z').filter(c -> N.isLetterOrDigit(c)).limit(12).toArray())

Случайный не означает, что он должен быть уникальным. для получения уникальных строк, используя:

N.uuid() // e.g.: "e812e749-cf4c-4959-8ee1-57829a69a80f". length is 36.
N.guid() // e.g.: "0678ce04e18945559ba82ddeccaabfcd". length is 32 without '-'
3
ответ дан 3 revs, 2 users 89% 19 August 2018 в 09:45
поделиться
  1. Измените строковые символы в соответствии с вашими требованиями.
  2. Строка неизменна. Здесь StringBuilder.append более эффективен, чем конкатенация строк.

public static String getRandomString(int length) {
       final String characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJLMNOPQRSTUVWXYZ1234567890!@#$%^&*()_+";
       StringBuilder result = new StringBuilder();
       while(length > 0) {
           Random rand = new Random();
           result.append(characters.charAt(rand.nextInt(characters.length())));
           length--;
       }
       return result.toString();
    }
5
ответ дан 3 revs, 2 users 91% 19 August 2018 в 09:45
поделиться
  • 1
    Это не добавляет ничего, о чем не говорили десятки ответов, данных ранее. И создание нового экземпляра Random на каждой итерации цикла неэффективно. – erickson 10 February 2014 в 07:17

Вы можете использовать следующий код, если ваш пароль обязательно содержит номера буквенных специальных символов:

private static final String NUMBERS = "0123456789";
private static final String UPPER_ALPHABETS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
private static final String LOWER_ALPHABETS = "abcdefghijklmnopqrstuvwxyz";
private static final String SPECIALCHARACTERS = "@#$%&*";
private static final int MINLENGTHOFPASSWORD = 8;

public static String getRandomPassword() {
    StringBuilder password = new StringBuilder();
    int j = 0;
    for (int i = 0; i < MINLENGTHOFPASSWORD; i++) {
        password.append(getRandomPasswordCharacters(j));
        j++;
        if (j == 3) {
            j = 0;
        }
    }
    return password.toString();
}

private static String getRandomPasswordCharacters(int pos) {
    Random randomNum = new Random();
    StringBuilder randomChar = new StringBuilder();
    switch (pos) {
        case 0:
            randomChar.append(NUMBERS.charAt(randomNum.nextInt(NUMBERS.length() - 1)));
            break;
        case 1:
            randomChar.append(UPPER_ALPHABETS.charAt(randomNum.nextInt(UPPER_ALPHABETS.length() - 1)));
            break;
        case 2:
            randomChar.append(SPECIALCHARACTERS.charAt(randomNum.nextInt(SPECIALCHARACTERS.length() - 1)));
            break;
        case 3:
            randomChar.append(LOWER_ALPHABETS.charAt(randomNum.nextInt(LOWER_ALPHABETS.length() - 1)));
            break;
    }
    return randomChar.toString();

}
3
ответ дан 3 revs, 2 users 99% 19 August 2018 в 09:45
поделиться
import java.util.Date;
import java.util.Random;

public class RandomGenerator {

  private static Random random = new Random((new Date()).getTime());

    public static String generateRandomString(int length) {
      char[] values = {'a','b','c','d','e','f','g','h','i','j',
               'k','l','m','n','o','p','q','r','s','t',
               'u','v','w','x','y','z','0','1','2','3',
               '4','5','6','7','8','9'};

      String out = "";

      for (int i=0;i<length;i++) {
          int idx=random.nextInt(values.length);
          out += values[idx];
      }
      return out;
    }
}
5
ответ дан 3 revs, 3 users 63% 19 August 2018 в 09:45
поделиться

В одной строке:

Long.toHexString(Double.doubleToLongBits(Math.random()));

http://mynotes.wordpress.com/2009/07/23/java-generating-random-string/

91
ответ дан 3 revs, 3 users 71%anonymous 19 August 2018 в 09:45
поделиться
  • 1
    Но только 6 букв :( – Moshe Revah 11 January 2011 в 10:45
  • 2
    Это помогло мне, но только шестнадцатеричные цифры :( – noquery 5 September 2011 в 06:31
  • 3
    @Zippoxer, вы могли бы конкаттировать это несколько раз =) – daniel.bavrin 17 May 2014 в 16:10
  • 4
    Пример OP показал следующую строку в качестве примера AEYGF7K0DM1X, который не является шестнадцатеричным. Меня беспокоит, как часто люди ошибочно принимают буквенно-цифровые символы с шестнадцатеричным. Это не одно и то же. – hfontanez 20 November 2014 в 03:31
  • 5
    Это намного менее случайное, чем следует указывать длину строки, поскольку Math.random() создает double между 0 и 1, поэтому экспоненциальная часть в основном не используется. Используйте random.nextLong для случайного long вместо этого уродливого взлома. – maaartinus 22 July 2015 в 01:13
import java.util.*;
import javax.swing.*;
public class alphanumeric{
    public static void main(String args[]){
        String nval,lenval;
        int n,len;

        nval=JOptionPane.showInputDialog("Enter number of codes you require : ");
        n=Integer.parseInt(nval);

        lenval=JOptionPane.showInputDialog("Enter code length you require : ");
        len=Integer.parseInt(lenval);

        find(n,len);

    }
    public static void find(int n,int length) {
        String str1="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        StringBuilder sb=new StringBuilder(length);
        Random r = new Random();

        System.out.println("\n\t Unique codes are \n\n");
        for(int i=0;i<n;i++){
            for(int j=0;j<length;j++){
                sb.append(str1.charAt(r.nextInt(str1.length())));
            }
            System.out.println("  "+sb.toString());
            sb.delete(0,length);
        }
    }
}
4
ответ дан 4 revs, 4 users 60% 19 August 2018 в 09:45
поделиться

Я нашел это решение, которое генерирует случайную шестнадцатеричную кодированную строку. Представленный модульный тест, похоже, подходит для моего основного использования. Хотя, это немного сложнее, чем некоторые другие предоставленные ответы.

/**
 * Generate a random hex encoded string token of the specified length
 *  
 * @param length
 * @return random hex string
 */
public static synchronized String generateUniqueToken(Integer length){ 
    byte random[] = new byte[length];
    Random randomGenerator = new Random();
    StringBuffer buffer = new StringBuffer();

    randomGenerator.nextBytes(random);

    for (int j = 0; j < random.length; j++) {
        byte b1 = (byte) ((random[j] & 0xf0) >> 4);
        byte b2 = (byte) (random[j] & 0x0f);
        if (b1 < 10)
            buffer.append((char) ('0' + b1));
        else
            buffer.append((char) ('A' + (b1 - 10)));
        if (b2 < 10)
            buffer.append((char) ('0' + b2));
        else
            buffer.append((char) ('A' + (b2 - 10)));
    }
    return (buffer.toString());
}

@Test
public void testGenerateUniqueToken(){
    Set set = new HashSet();
    String token = null;
    int size = 16;

    /* Seems like we should be able to generate 500K tokens 
     * without a duplicate 
     */
    for (int i=0; i<500000; i++){
        token = Utility.generateUniqueToken(size);

        if (token.length() != size * 2){
            fail("Incorrect length");
        } else if (set.contains(token)) {
            fail("Duplicate token generated");
        } else{
            set.add(token);
        }
    }
}
5
ответ дан 4 revs, 4 users 80% 19 August 2018 в 09:45
поделиться
  • 1
    Я не думаю, что справедливо терпеть неудачу для повторяющихся токенов, которые основаны исключительно на вероятности. – Thom Wiggers 2 June 2012 в 16:22

с использованием Доллар должен быть простым:

// "0123456789" + "ABCDE...Z"
String validCharacters = $('0', '9').join() + $('A', 'Z').join();

String randomString(int length) {
    return $(validCharacters).shuffle().slice(length).toString();
}

@Test
public void buildFiveRandomStrings() {
    for (int i : $(5)) {
        System.out.println(randomString(12));
    }
}

выводит что-то вроде этого:

DKL1SBH9UJWC
JH7P0IT21EA5
5DTI72EO6SFU
HQUMJTEBNF7Y
1HCR6SKYWGT7
37
ответ дан 4 revs, 4 users 83% 19 August 2018 в 09:45
поделиться
static final String AB = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
static SecureRandom rnd = new SecureRandom();

String randomString( int len ){
   StringBuilder sb = new StringBuilder( len );
   for( int i = 0; i < len; i++ ) 
      sb.append( AB.charAt( rnd.nextInt(AB.length()) ) );
   return sb.toString();
}
469
ответ дан 5 revs, 5 users 72% 19 August 2018 в 09:45
поделиться
  • 1
    +1, простейшее решение здесь для генерации случайной строки указанной длины (кроме использования RandomStringUtils из Commons Lang). – Jonik 20 April 2012 в 16:49
  • 2
    Подумайте об использовании SecureRandom вместо класса Random. Если пароли генерируются на сервере, это может быть уязвимо для временных атак. – foens 25 June 2014 в 14:34
  • 3
    Я бы добавил также строчные буквы: AB = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; и некоторые другие допустимые символы. – ACV 7 September 2015 в 20:56
  • 4
    Почему бы не поставить static Random rnd = new Random(); внутри метода? – Micro 8 February 2016 в 02:25
  • 5
    @MicroR Есть ли веская причина для создания объекта Random в каждом вызове метода? Я так не думаю. – Cassio Mazzochi Molin 15 February 2016 в 11:49

Краткое и простое решение, но использует только строчные буквы и числовые значения:

Random r = new java.util.Random ();
String s = Long.toString (r.nextLong () & Long.MAX_VALUE, 36);

Размер составляет от 12 цифр до основания 36 и не может быть улучшен дальше. Конечно, вы можете добавить несколько экземпляров.

21
ответ дан 7 revs, 4 users 78% 19 August 2018 в 09:45
поделиться
  • 1
    Просто имейте в виду, что есть 50% -ый шанс минус-знака infront результата! Таким образом, можно использовать обертку r.nextLong () в Math.abs (), если вы не хотите знак минуса: Long.toString(Math.abs(r.nextLong()), 36); – Ray Hulha 27 January 2013 в 04:12
  • 2
    @RayHulha: Если вы не хотите знак минус, вы должны его отключить, потому что, как ни удивительно, Math.abs возвращает отрицательное значение для Long.MIN_VALUE. – user unknown 27 January 2013 в 15:28
  • 3
    Интересно, что Math.abs возвращает отрицательный результат. Подробнее здесь: bmaurer.blogspot.co.nz/2006/10/… – Phil 10 November 2013 в 22:34
  • 4
    Проблема с abs решена с помощью побитового оператора для очистки самого значимого бита. Это будет работать для всех значений. – Radiodef 2 April 2018 в 23:27
  • 5
    @Radiodef Вот что сказал @userunkown. Я полагаю, вы могли бы также сделать << 1 >>> 1. – shmosel 2 April 2018 в 23:35

Java предоставляет способ сделать это напрямую. Если вы не хотите тире, их легко вырезать. Просто используйте uuid.replace("-", "")

import java.util.UUID;

public class randomStringGenerator {
    public static void main(String[] args) {
        System.out.println(generateString());
    }

    public static String generateString() {
        String uuid = UUID.randomUUID().toString();
        return "uuid = " + uuid;
    }
}

Выход:

uuid = 2d7428a6-b58c-4008-8575-f05549f16316
736
ответ дан 7 revs, 6 users 50% 19 August 2018 в 09:45
поделиться
  • 1
    Помните, что это решение генерирует только случайную строку с шестнадцатеричными символами. В некоторых случаях это может быть хорошо. – Dave 5 May 2011 в 10:28
  • 2
    Класс UUID полезен. Однако они не настолько компактны, как идентификаторы, созданные моими ответами. Это может быть проблемой, например, в URL-адресах. Зависит от ваших потребностей. – erickson 24 August 2011 в 17:37
  • 3
    @Ruggs. Цель - буквенно-числовые строки. Как расширяется вывод на любые возможные байты? – erickson 7 October 2011 в 17:18
  • 4
    Согласно RFC4122, использование UUID в качестве токенов - плохая идея: не предполагайте, что UUID трудно догадаться; они не должны использоваться в качестве возможностей безопасности (например, идентификаторы, чье личное владение предоставляет доступ). Предполагаемый источник случайных чисел усугубит ситуацию. ietf.org/rfc/rfc4122.txt – Somatik 31 December 2012 в 13:31
  • 5
    UUID.randomUUID().toString().replaceAll("-", ""); делает строку буквенно-числовой, как и требовалось. – Numid 22 January 2014 в 11:58

Здесь он находится в Java:

import static java.lang.Math.round;
import static java.lang.Math.random;
import static java.lang.Math.pow;
import static java.lang.Math.abs;
import static java.lang.Math.min;
import static org.apache.commons.lang.StringUtils.leftPad

public class RandomAlphaNum {
  public static String gen(int length) {
    StringBuffer sb = new StringBuffer();
    for (int i = length; i > 0; i -= 12) {
      int n = min(12, abs(i));
      sb.append(leftPad(Long.toString(round(random() * pow(36, n)), 36), n, '0'));
    }
    return sb.toString();
  }
}

Вот пример:

scala> RandomAlphaNum.gen(42)
res3: java.lang.String = uja6snx21bswf9t89s00bxssu8g6qlu16ffzqaxxoy
28
ответ дан Apocalisp 19 August 2018 в 09:45
поделиться
  • 1
    Это создаст неустойчивые последовательности , т.е. последовательности, которые можно легко догадаться. – Yura 3 April 2014 в 15:53
  • 2
    и leftPad ???? – lahbib 19 March 2015 в 18:53
  • 3
    Все это двойное зараженное случайное int-поколение нарушено дизайном, медленным и нечитаемым. Используйте Random#nextInt или nextLong. При необходимости переключитесь на SecureRandom. – maaartinus 22 July 2015 в 01:17

Лучший метод генератора случайных строк

public class RandomStringGenerator{

    private static int randomStringLength = 25 ;
    private static boolean allowSpecialCharacters = true ;
    private static String specialCharacters = "!@$%*-_+:";
    private static boolean allowDuplicates = false ;

    private static boolean isAlphanum = false;
    private static boolean isNumeric = false;
    private static boolean isAlpha = false;
    private static final String alphabet = "abcdefghijklmnopqrstuvwxyz";
    private static boolean mixCase = false;
    private static final String capAlpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    private static final String num = "0123456789";

    public static String getRandomString() {
        String returnVal = "";
        int specialCharactersCount = 0;
        int maxspecialCharacters = randomStringLength/4;

        try {
            StringBuffer values = buildList();
            for (int inx = 0; inx < randomStringLength; inx++) {
                int selChar = (int) (Math.random() * (values.length() - 1));
                if (allowSpecialCharacters)
                {
                    if (specialCharacters.indexOf("" + values.charAt(selChar)) > -1)
                    {
                        specialCharactersCount ++;
                        if (specialCharactersCount > maxspecialCharacters)
                        {
                            while (specialCharacters.indexOf("" + values.charAt(selChar)) != -1)
                            {
                                selChar = (int) (Math.random() * (values.length() - 1));
                            }
                        }
                    }
                }
                returnVal += values.charAt(selChar);
                if (!allowDuplicates) {
                    values.deleteCharAt(selChar);
                }
            }
        } catch (Exception e) {
            returnVal = "Error While Processing Values";
        }
        return returnVal;
    }

    private static StringBuffer buildList() {
        StringBuffer list = new StringBuffer(0);
        if (isNumeric || isAlphanum) {
            list.append(num);
        }
        if (isAlpha || isAlphanum) {
            list.append(alphabet);
            if (mixCase) {
                list.append(capAlpha);
            }
        }
        if (allowSpecialCharacters)
        {
            list.append(specialCharacters);
        }
        int currLen = list.length();
        String returnVal = "";
        for (int inx = 0; inx < currLen; inx++) {
            int selChar = (int) (Math.random() * (list.length() - 1));
            returnVal += list.charAt(selChar);
            list.deleteCharAt(selChar);
        }
        list = new StringBuffer(returnVal);
        return list;
    }   

}
1
ответ дан Bhavik Ambani 19 August 2018 в 09:45
поделиться
import java.util.Random;

public class passGen{
    //Verison 1.0
    private static final String dCase = "abcdefghijklmnopqrstuvwxyz";
    private static final String uCase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    private static final String sChar = "!@#$%^&*";
    private static final String intChar = "0123456789";
    private static Random r = new Random();
    private static String pass = "";

    public static void main (String[] args) {
        System.out.println ("Generating pass...");
        while (pass.length () != 16){
            int rPick = r.nextInt(4);
            if (rPick == 0){
                int spot = r.nextInt(25);
                pass += dCase.charAt(spot);
            } else if (rPick == 1) {
                int spot = r.nextInt (25);
                pass += uCase.charAt(spot);
            } else if (rPick == 2) {
                int spot = r.nextInt (7);
                pass += sChar.charAt(spot);
            } else if (rPick == 3){
                int spot = r.nextInt (9);
                pass += intChar.charAt (spot);
            }
        }
        System.out.println ("Generated Pass: " + pass);
    }
}

Итак, что это такое, просто добавьте пароль в строку и ... да, хорошо проверите это ... очень просто. Я написал это

7
ответ дан cmpbah 19 August 2018 в 09:45
поделиться
  • 1
    Я позволил себе внести некоторые незначительные изменения. Почему вы часто добавляете + 0? Почему вы разделяете объявление пятна и initialisxation? В чем преимущество индексов 1,2,3,4 вместо 0,1,2,3? Самое главное: вы взяли случайное значение и сравнили с if-else 4 раза новое значение, которое всегда могло бы не соответствовать, не получая больше случайности. Но не стесняйтесь отката. – user unknown 17 April 2012 в 10:50

Альтернатива в Java 8:

static final Random random = new Random(); // Or SecureRandom
static final int startChar = (int) '!';
static final int endChar = (int) '~';

static String randomString(final int maxLength) {
  final int length = random.nextInt(maxLength + 1);
  return random.ints(length, startChar, endChar + 1)
        .mapToObj((i) -> (char) i)
        .collect(StringBuilder::new, StringBuilder::append, StringBuilder::append)
        .toString();
}
11
ответ дан Howard Lovatt 19 August 2018 в 09:45
поделиться

с использованием библиотеки apache это можно сделать в одной строке

import org.apache.commons.lang.RandomStringUtils;
RandomStringUtils.randomAlphanumeric(64);

здесь doc http://commons.apache.org/lang/api-2.3/org/apache/commons /lang/RandomStringUtils.html

2
ответ дан hridayesh 19 August 2018 в 09:45
поделиться

Вы можете использовать класс UUID с его сообщением getLeastSignificantBits (), чтобы получить 64 бит случайных данных, а затем преобразовать его в число radix 36 (т.е. строку, состоящую из 0-9, AZ):

Long.toString(Math.abs( UUID.randomUUID().getLeastSignificantBits(), 36));

Это дает строку длиной до 13 символов. Мы используем Math.abs (), чтобы убедиться, что нет знака минус.

3
ответ дан neuhaus 19 August 2018 в 09:45
поделиться
  • 1
    Почему в мире вы бы использовали UUID для получения случайных бит? Почему бы просто не использовать random.nextLong()? Или даже Double.doubleToLongBits(Math.random())? – erickson 4 October 2013 в 06:31
public static String generateSessionKey(int length){
String alphabet = 
        new String("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"); //9
int n = alphabet.length(); //10

String result = new String(); 
Random r = new Random(); //11

for (int i=0; i<length; i++) //12
    result = result + alphabet.charAt(r.nextInt(n)); //13

return result;
}
8
ответ дан rina 19 August 2018 в 09:45
поделиться

Здесь это решение Scala:

(for (i <- 0 until rnd.nextInt(64)) yield { 
  ('0' + rnd.nextInt(64)).asInstanceOf[Char] 
}) mkString("")
3
ответ дан Ugo Matrangolo 19 August 2018 в 09:45
поделиться
public static String getRandomString(int length) 
{
   String randomStr = UUID.randomUUID().toString();
   while(randomStr.length() < length) {
       randomStr += UUID.randomUUID().toString();
   }
   return randomStr.substring(0, length);
}
1
ответ дан Vin Ferothas 19 August 2018 в 09:45
поделиться

Использование UUID небезопасно, потому что части UUID вообще не случайны. Процедура @erickson очень аккуратная, но не создает строки одинаковой длины. Следующий фрагмент должен быть достаточным:

/*
 * The random generator used by this class to create random keys.
 * In a holder class to defer initialization until needed.
 */
private static class RandomHolder {
    static final Random random = new SecureRandom();
    public static String randomKey(int length) {
        return String.format("%"+length+"s", new BigInteger(length*5/*base 32,2^5*/, random)
            .toString(32)).replace('\u0020', '0');
    }
}

Зачем выбирать length*5. Предположим простой случай случайной строки длины 1, поэтому один случайный символ. Чтобы получить случайный символ, содержащий все цифры 0-9 и символы a-z, нам понадобится случайное число от 0 до 35, чтобы получить один из каждого символа. BigInteger предоставляет конструктор для генерации случайного числа, равномерно распределенного по диапазону 0 to (2^numBits - 1). К сожалению, 35 не является числом, которое может быть получено 2 ^ numBits - 1. Таким образом, у нас есть два варианта: либо пойти с 2^5-1=31, либо 2^6-1=63. Если бы мы выбрали 2^6, мы получили бы много «лишних» / «более длинных» чисел. Поэтому 2^5 - лучший вариант, даже если мы потеряем 4 символа (w-z). Чтобы сгенерировать строку определенной длины, мы можем просто использовать номер 2^(length*numBits)-1. Последняя проблема, если нам нужна строка с определенной длиной, случайный может генерировать небольшое число, поэтому длина не выполняется, поэтому нам нужно наложить строку на требуемую длину, добавляя нули.

8
ответ дан 3 revs 19 August 2018 в 09:45
поделиться
Другие вопросы по тегам:

Похожие вопросы: