总结
拼接字符串最好不要直接用 “+” ,因为编译器遇到 “+” 的时候,会 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 | /** |