我一直在寻找一种简单的Java算法来生成伪随机字母数字字符串。在我的情况下,它将被用作唯一的会话/密钥标识符,“很可能”在超过50万代的时间内是唯一的(我的需求实际上不需要更复杂的东西)。

理想情况下,我可以根据我的独特性需求指定长度。例如,生成的长度为12的字符串可能看起来像“AEYGF7K0DM1X”。


当前回答

public static String RandomAlphanum(int length)
{
    String charstring = "abcdefghijklmnopqrstuvwxyz0123456789";
    String randalphanum = "";
    double randroll;
    String randchar;
    for (double i = 0; i < length; i++)
    {
        randroll = Math.random();
        randchar = "";
        for (int j = 1; j <= 35; j++)
        {
            if (randroll <= (1.0 / 36.0 * j))
            {
                randchar = Character.toString(charstring.charAt(j - 1));
                break;
            }
        }
        randalphanum += randchar;
    }
    return randalphanum;
}

我使用Math.random()使用了一个非常原始的算法。为了增加随机性,可以直接实现util.Date类。尽管如此,它还是有效的。

其他回答

public class Utils {
    private final Random RANDOM = new SecureRandom();
    private final String ALPHABET = "0123456789QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm";

    private String generateRandomString(int length) {
        StringBuffer buffer = new StringBuffer(length);
        for (int i = 0; i < length; i++) {
            buffer.append(ALPHABET.charAt(RANDOM.nextInt(ALPHABET.length())));
        }
        return new String(buffer);
    } 
}

这里是一个基于流的Java8解决方案。

    public String generateString(String alphabet, int length) {
        return generateString(alphabet, length, new SecureRandom()::nextInt);
    }

    // nextInt = bound -> n in [0, bound)
    public String generateString(String source, int length, IntFunction<Integer> nextInt) {
        StringBuilder sb = new StringBuilder();
        IntStream.generate(source::length)
                .boxed()
                .limit(length)
                .map(nextInt::apply)
                .map(source::charAt)
                .forEach(sb::append);

        return sb.toString();
    }

像这样使用

String alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
int length = 12;
String generated = generateString(alphabet, length);
System.out.println(generated);

函数nextInt应该接受一个int绑定,并返回一个介于0和绑定-1之间的随机数。

我不太喜欢这些关于“简单”解决方案的答案: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")); // The character set 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")); // The character set can basically be anything
    }
}

但另一方面,你也可以使用UUID,它具有相当好的熵:

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

使用美元应简单如下:

// "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

高效而简短。

/**
 * Utility class for generating random Strings.
 */
public interface RandomUtil {

    int    DEF_COUNT = 20;
    Random RANDOM    = new SecureRandom();

    /**
     * Generate a password.
     *
     * @return the generated password
     */
    static String generatePassword() {
        return generate(true, true);
    }

    /**
     * Generate an activation key.
     *
     * @return the generated activation key
     */
    static String generateActivationKey() {
        return generate(false, true);
    }

    /**
     * Generate a reset key.
     *
     * @return the generated reset key
     */
    static String generateResetKey() {
        return generate(false, true);
    }

    static String generate(boolean letters, boolean numbers) {
        int
            start = ' ',
            end   = 'z' + 1,
            count = DEF_COUNT,
            gap   = end - start;
        StringBuilder builder = new StringBuilder(count);

        while (count-- != 0) {
            int codePoint = RANDOM.nextInt(gap) + start;

            switch (getType(codePoint)) {
                case UNASSIGNED:
                case PRIVATE_USE:
                case SURROGATE:
                    count++;
                    continue;
            }

            int numberOfChars = charCount(codePoint);

            if (count == 0 && numberOfChars > 1) {
                count++;
                continue;
            }

            if (letters && isLetter(codePoint)
                || numbers && isDigit(codePoint)
                || !letters && !numbers) {

                builder.appendCodePoint(codePoint);
                if (numberOfChars == 2)
                    count--;
            }
            else
                count++;
        }
        return builder.toString();
    }
}