4

生成任意特定长度的随机字符串。我知道这个问题已经被问过很多次了,我在下面写了这段代码,我只是想知道有没有比我写的下面的代码更好的方法?或者我们可以让下面的代码更高效?

public static void main(String[] args) {
    String s = randomString(25);
    System.out.println(s);
}

public static String randomString(final int length) {
    StringBuilder sb = new StringBuilder();
    Random r = new Random();
    String subset = "0123456789abcdefghijklmnopqrstuvwxyz";
    for (int i = 0; i < length; i++) {
        int index = r.nextInt(subset.length());
        char c = subset.charAt( index );
        sb.append( c );
    }
    return sb.toString();
}
4

5 回答 5

4

由于您提前知道长度,因此使用容量设置 StringBuilder:

StringBuilder sb = new StringBuilder(length);

仅此一项就消除了在 StringBuilder 中不必要地调整内部数组的大小。

话虽如此,您最好使用 char[] 数组而不是 StringBuilder,并且也将子集表示为 char[]。

private static final char [] subset = "0123456789abcdefghijklmnopqrstuvwxyz".toCharArray();

char buf[] = new char[length];
for (int i=0;i<buf.length;i++) {
  int index = r.nextInt(subset.length);
  buf[i] = subset[index];
}

return new String(buf);

通过避免对“charAt”和“append”的一些函数调用开销,这里可以获得一些微妙的收益。以及消除 StringBuilder 的一些内存和分配时间开销。一般来说,如果您知道要构建的字符串的大小,那么直接使用 char 数组会更有效率。

于 2012-05-27T02:52:45.210 回答
3

首先,您可能不需要提高此方法的性能。该方法的调用频率可能不够高,以至于对其进行优化会对应用程序的整体性能产生显着影响。您应该在此级别进行优化之前分析您的应用程序,否则您可能会浪费时间在没有任何区别的东西上。

其次,即使这是一个值得的优化,您仍然需要分析您的应用程序以确定哪些优化效果最好……以及优化工作是否真的产生了任何影响。


如果(假设地)我试图让这个过程尽可能快,我会试试这个:

private static final char[] subset = 
        "0123456789abcdefghijklmnopqrstuvwxyz".toCharArray();
private static final Random prng = new Random();
...
public static String randomString(final int length) {
    char[] chars = new char[length];
    final int subsetLength = subsetLength;
    for (int i = 0; i < length; i++) {
        int index = prng.nextInt(subsetLength);
        chars[i] = subset[index];
    }
    return new String(chars);
}

总之:

  1. 不要Random每次都创建一个新实例。这可能是最大的优化,因为创建实例通常涉及获取随机种子的系统调用。
  2. StringBuilder当 a工作正常时不要使用 a char[]
  3. 避免charAt.
  4. 在可能的情况下,将一次性任务从循环和方法调用中提升出来。

(请注意,第 3 点和第 4 点可能会变得不值得;即 JIT 编译器可能足够聪明,可以为您进行相同的优化……如果您允许的话。)

于 2012-05-27T03:03:50.510 回答
1

仅使用指定的字符串和长度创建一个随机字符串。你使用RandomStringUtils。如果要生成随机字符串RandomStringUtils#random 例如:指定字符串,长度为 25

private static final SecureRandom RANDOM = new SecureRandom();
private static final char[] PASSWORD_CHARS=("0123456789abcdefghijklmnopqrstuvwxyz").toCharArray();
String passwd=RandomStringUtils.random(25, 0, PASSWORD_CHARS.length, false, false, PASSWORD_CHARS, RANDOM);
于 2012-05-27T09:30:43.830 回答
1

您可以直接转换为并使用它,而不是使用Strings 。intchar

// 36 total alpha-numeric characters
int size = 36;

for (int i=0; i<length; i++) {
    // num is an integer from 0-35
    int num = r.nextInt(size);

    if (num < 26) {
        // Then we add a lowercase character
        sb.append((char)('a'+num));
    } else {
        // then we add a digit 0-9
        sb.append((char)('0'+(num-26)));
    }
}

其他可能的优化:

  1. 使用固定大小的 achar[]而不是StringBuilder.
  2. 将您的字符串定义subsetstaticand final

当然,这些优化非常微不足道,在这个问题的上下文中不会对您的程序产生太大影响。


编辑:

如果您需要生成String具有固定字符集的随机数,那么我上面提到的方法将不起作用。您必须String像在帖子中那样使用包含字符的字符。

于 2012-05-27T02:18:56.667 回答
0

如果您想最小化对随机生成器的调用,您可以从每个随机整数中生成 5 个字符。但此实现仅适用于您的精确 36 字符集:(0123456789abcdefghijklmnopqrstuvwxyz请参阅Integer.toString() Javadoc)。而且这种实现的模糊性不可能补偿性能增益。

private static final int range = 36 * 36 * 36 * 36 * 36; // 36^5 is less than 2^31
private static Random rand = new Random();
private static String zeroes="00000";

public static String generate(int length) {
    StringBuilder sb = new StringBuilder(length+5);
    while (sb.length() < length) {
        String x = Integer.toString(rand.nextInt(range), 36);
        if(x.length()<5)
            sb.append(zeroes.substring(0, 5-x.length()));
        sb.append(x);
    }
    return sb.substring(0, length);
}

零附加保证了字符是均匀随机的(没有它,字符0出现的频率会比其他字符略低)。

于 2012-05-27T03:36:56.013 回答