Как сгенерировать случайную буквенно-цифровую строку в Java?
Лучший способ: использование SecureRandom и готового набора символов
Ваш подход в целом рабочий, но есть несколько важных улучшений. Главная проблема — использование Math.random(), который не подходит для криптографически стойких токенов. Для генерации паролей и идентификаторов используйте java.security.SecureRandom. Вот оптимальное решение:
import java.security.SecureRandom;
import java.util.Locale;
import java.util.Objects;
import java.util.Random;
public class RandomStringGenerator {
private static final String UPPER = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
private static final String LOWER = UPPER.toLowerCase(Locale.ROOT);
private static final String DIGITS = "0123456789";
private static final String ALPHANUM = UPPER + LOWER + DIGITS;
private final Random random;
private final char[] symbols;
private final char[] buf;
public RandomStringGenerator(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];
}
/**
* Создаёт генератор для буквенно-цифровых строк заданной длины.
*/
public RandomStringGenerator(int length, Random random) {
this(length, random, ALPHANUM);
}
/**
* Создаёт генератор с SecureRandom по умолчанию.
*/
public RandomStringGenerator(int length) {
this(length, new SecureRandom());
}
public String nextString() {
for (int idx = 0; idx < buf.length; ++idx) {
buf[idx] = symbols[random.nextInt(symbols.length)];
}
return new String(buf);
}
// Пример использования:
public static void main(String[] args) {
RandomStringGenerator gen = new RandomStringGenerator(10);
System.out.println(gen.nextString()); // например: "k3R9tB2xQ7"
}
}
Почему это решение лучше?
- Безопасность:
SecureRandomиспользует криптографически стойкий генератор (например, /dev/urandom на Linux).Math.random()предсказуем и не подходит для токенов. - Производительность: Массив символов
bufпереиспользуется для всех вызововnextString(), что снижает нагрузку на сборщик мусора. - Гибкость: Вы можете легко менять набор символов — убрать цифры, добавить спецсимволы или использовать только заглавные буквы.
- Чистота кода: Вся логика инкапсулирована в одном классе, легко тестируется и переиспользуется.
Короткий однострочник для простых случаев
Если вам не нужна кастомная настройка и безопасность не критична (например, для тестовых данных), можно использовать Apache Commons Lang:
import org.apache.commons.lang3.RandomStringUtils;
String result = RandomStringUtils.randomAlphanumeric(10);
// Результат: "aB3dE5fG7h"
Но для продакшена рекомендую первый вариант с SecureRandom.
Альтернативный подход: генерация на основе UUID с фильтрацией
Если вам лень писать свой генератор, можно адаптировать встроенный UUID. Удалите из него дефисы и возьмите нужное количество символов:
import java.util.UUID;
public static String generateFromUUID(int length) {
String uuid = UUID.randomUUID().toString().replace("-", "");
// UUID содержит 32 символа (0-9, a-f), без заглавных букв
return uuid.substring(0, Math.min(length, 32));
}
Минусы этого подхода:
- UUID использует только шестнадцатеричные символы (0-9, a-f), что сужает алфавит до 16 символов вместо 62.
- Нет заглавных букв, что снижает энтропию (для 10-символьной строки: 16^10 вместо 62^10 комбинаций).
- Максимальная длина — 32 символа.
Когда это уместно: Для генерации коротких идентификаторов в небезопасных сценариях (например, для логов или тестовых данных). Для паролей и токенов — не используйте.
Ещё один простой вариант — использовать java.util.Random с вашим исходным кодом, но заменить Math.random() на random.nextInt(chars.length()). Это даст более равномерное распределение:
Random random = new Random();
String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
StringBuilder sb = new StringBuilder();
for (int i = 0; i < length; i++) {
sb.append(chars.charAt(random.nextInt(chars.length())));
}
return sb.toString();
Этот код проще, но всё ещё не криптостойкий. Для большинства задач лучше использовать первый ответ с SecureRandom.