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

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


当前回答

我使用的是一个非常简单的Java8解决方案。只需根据您的需求进行定制。

...
import java.security.SecureRandom;
...

//Generate a random String of length between 10 to 20.
//Length is also randomly generated here.
SecureRandom random = new SecureRandom();

String sampleSet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_";

int stringLength = random.ints(1, 10, 21).mapToObj(x -> x).reduce((a, b) -> a).get();

String randomString = random.ints(stringLength, 0, sampleSet.length() - 1)
        .mapToObj(x -> sampleSet.charAt(x))
        .collect(Collector
            .of(StringBuilder::new, StringBuilder::append,
                StringBuilder::append, StringBuilder::toString));

我们可以使用它生成如下的字母数字随机字符串(返回的字符串将强制包含一些非数字字符以及一些数字字符):

public String generateRandomString() {
            
    String sampleSet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_";
    String sampleSetNumeric = "0123456789";
    
    String randomString = getRandomString(sampleSet, 10, 21);
    String randomStringNumeric = getRandomString(sampleSetNumeric, 10, 21);
    
    randomString = randomString + randomStringNumeric;
    
    //Convert String to List<Character>
    List<Character> list = randomString.chars()
            .mapToObj(x -> (char)x)
            .collect(Collectors.toList());
    
    Collections.shuffle(list);
    
    //This is needed to force a non-numeric character as the first String
    //Skip this for() if you don't need this logic

    for(;;) {
        if(Character.isDigit(list.get(0))) Collections.shuffle(list);
        else break;
    }
    
    //Convert List<Character> to String
    randomString = list.stream()
            .map(String::valueOf)
            .collect(Collectors.joining());
    
    return randomString;
    
}

//Generate a random number between the lower bound (inclusive) and upper bound (exclusive)
private int getRandomLength(int min, int max) {
    SecureRandom random = new SecureRandom();
    return random.ints(1, min, max).mapToObj(x -> x).reduce((a, b) -> a).get();
}

//Generate a random String from the given sample string, having a random length between the lower bound (inclusive) and upper bound (exclusive)
private String getRandomString(String sampleSet, int min, int max) {
    SecureRandom random = new SecureRandom();
    return random.ints(getRandomLength(min, max), 0, sampleSet.length() - 1)
    .mapToObj(x -> sampleSet.charAt(x))
    .collect(Collector
        .of(StringBuilder::new, StringBuilder::append,
            StringBuilder::append, StringBuilder::toString));
}

其他回答

这是算盘常用的一行:

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 '-'

您可以为此使用Apache Commons库RandomStringUtils:

RandomStringUtils.randomAlphanumeric(20).toUpperCase();

您可以使用UUID类及其getLeastSignificantBits()消息来获取64位随机数据,然后将其转换为基数36的数字(即由0-9、a-Z组成的字符串):

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

这将产生一个长达13个字符的字符串。我们使用Math.abs()来确保没有负号潜入。

一个简单的解决方案,但它只使用小写和数字:

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

大小约为12位数,以36为基数,这样就无法进一步改进。当然,您可以附加多个实例。

这里是Scala解决方案:

(for (i <- 0 until rnd.nextInt(64)) yield { 
  ('0' + rnd.nextInt(64)).asInstanceOf[Char] 
}) mkString("")