性能改进(生成任意长度的随机字符串)

时间:2012-05-27 02:06:29

标签: java string random

生成任意长度的随机字符串。我知道这个问题已被多次询问,我在下面编写了这段代码,我只是想知道有没有更好的方法,然后我写下面的代码?或者我们可以使下面的代码更有效率?

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();
}

5 个答案:

答案 0 :(得分: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工作正常时,请勿使用char[]
  3. 避免charAt。(/ li>)的(小)开销
  4. 尽可能在循环和方法调用之外提升一次性任务。
  5. (请注意,第3点和第4点可能不值得;即JIT编译器可能足够聪明,可以为您进行相同的优化...如果你只是让它。)

答案 1 :(得分:2)

由于您事先知道长度,因此请使用容量设置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数组会更有效。

答案 2 :(得分:1)

您可以将String投射到int并直接使用char,而不是使用// 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))); } }

char[]

其他可能的优化:

  1. 使用固定大小的StringBuilder而不是subset
  2. 将您的static字符串定义为finalString
  3. 当然,这些优化非常简单,在这个问题的背景下对你的程序没有太大的影响。


    编辑:

    如果您需要使用一组固定的字符生成随机String,那么我上面提到的方法将无效。您必须使用包含字符的{{1}},就像您在帖子中所做的那样。

答案 3 :(得分: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);

答案 4 :(得分: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的出现频率会比其他角色慢得多)。