总结
拼接字符串最好不要直接用 “+” ,因为编译器遇到 “+” 的时候,会 new 一个 StringBuilder 出来,接着调用 append 方法进行追加,再调用 toString 方法,生成新字符串。在每次循环中,都会创建一个 StringBuilder 对象,且都会调用一次 toString 方法,可见用 “+” 拼接字符串的成本是十分高的。
PS:执行一次字符串 “str += a”,相当于 “str = new StringBuilder(str).append(“a”).toString()”
String、StringBuilder、StringBuffer 的区别
String 为字符串常量,而 StringBuilder 和 StringBuffer 均为字符串变量,即 String 对象一旦创建之后该对象是不可更改的,但后两者的对象是变量,是可以更改的。
运行效率:StringBuilder > StringBuffer > String
StringBuffer 和 StringBuilder 都继承自 AbstractStringBuilder,原理一样,就是在底层维护了一个 char 数组,唯一的区别只是 StringBuffer 是线程安全的,它对所有方法都做了同步,而 StringBuilder 是非线程安全的。
| 1 | AbstractStringBuilder(int capacity) { | 
每次 append 的时候就会往 char[ ] 中填入字符,在最终调用 sb.toString( ) 的时候,用一个 new String( ) 方法把 char 数组里面的内容都转成 String,这样,整个过程中只产生了一个 StringBuilder 对象与一个 String 对象,非常节省空间。
StringBuilde r唯一的性能损耗点在于 char[ ] 容量不够的时候需要进行扩容,扩容需要进行数组拷贝,一定程度上降低了效率。
考虑到扩容的时候有性能上的损耗,尽量在初始化时预估长度并传入该长度,可以避免扩容的发生。
代码
第一次直接写的,感觉就是 foolish code……..1
2
3
4
5
6
7
8
9
10
11
12
13
14
15public String getCaptcha(int length) {
        String rnd = "";
        Random random = new Random();
        String[] str = {"A", "B", "C", "D", "E", "F", "G", "H", "J", "K",
                "L", "M", "N", "P", "Q", "R", "S", "T", "U", "V", "W", "X",
                "Y", "Z", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j",
                "k", "m", "n", "p", "s", "t", "u", "v", "w", "x", "y", "z",
                "1", "2", "3", "4", "5", "6", "7", "8", "9"};
        for (int i = 0; i < length; i++) {
            String rand = str[random.nextInt(str.length)];
            rnd += rand;
        }
        return rnd;
    }
}
第二次,想到最近看的 HashMap 源码中将模运算转为与运算,再改成用 ASCII 码计算验证码。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15public String getRandom(int length) {
        String rnd = "";
        Random random = new Random();
        for (int i = 0; i < length; i++) {
            // random.nextInt(2) & 1 = random.nextInt(2) % 2
            if ((random.nextInt(2) & 1) == 0) {
                int temp = (random.nextInt(2) & 1) == 0 ? 65 : 97;
                int ascii = random.nextInt(26);
                rnd += (char) (ascii + temp);
            } else {
                rnd += String.valueOf(random.nextInt(10));
            }
        }
        return rnd;
    }
第三次,考虑到《Effective Java》中指出,“不要使用字符串连接操作来合并多个字符串,除非性能无非紧要,应该使用 StringBuilder 的 append 方法。”1
2
3
4
5
6
7
8
9
10
11
12
13
14
15public String getRandom(int length) {
        StringBuilder sb = new StringBuilder(length);
        Random random = new Random();
        while (length--!=0) {
            // random.nextInt(2) & 1 = random.nextInt(2) % 2
            if ((random.nextInt(2) & 1) == 0) {
                int temp = (random.nextInt(2) & 1) == 0 ? 65 : 97;
                int ascii = random.nextInt(26);
                sb.append((char) (ascii + temp));
            } else {
                sb.append(String.valueOf(random.nextInt(10)));
            }
        }
        return sb.toString();
    }
或者直接使用已有的工具类RandomStringUtils :1
2
3public String getRandom(int length) {
        return RandomStringUtils.randomAlphanumeric(4);
    }
RandomStringUtils 中的实现
在 org.apache.commons.lang.RandomStringUtils 中的 RandomStringUtils 工具类可以实现生成随机字符串,其中生成字母和数字的随机组合的方法是:
public static String randomAlphanumeric(int count)
Creates a random string whose length is the number of characters specified.
Characters will be chosen from the set of alpha-numeric characters.
来看看它的源码具体实现:
| 1 | /** |