场景
java开发手册中对于循环体中进行字符串的拼接要求如下:
【推荐】循环体内,字符串的连接方式,使用 StringBuilder 的 append 方法进行扩展。
说明:下例中,反编译出的字节码文件显示每次循环都会 new 出一个 StringBuilder 对象,然后进行 append操作,
最后通过 toString 方法返回 String 对象,造成内存资源浪费。
并且还提供了反例:
String str = "start";
for (int i = 0; i < 100; i++) {
str = str + "hello";
}
Java中字符串占位替换、字符串拼接、字符串与Collection互转的方式:
Java中字符串占位替换、字符串拼接、字符串与Collection互转的方式_霸道流氓气质的博客-CSDN博客
字符串的拼接的几种方式可以参考上面的博客。
除了使用+拼接字符串之外,还可以使用 String 类中的方法 concat 方法来拼接字符串。
示例代码:
String a = "a";
String b = "b";
String c = a.concat(b);
System.out.println(c);
注:
博客:
霸道流氓气质的博客_CSDN博客-C#,架构之路,SpringBoot领域博主
下面看一下Java中String的concat方法的源码
// public String concat(String str) {
// int otherLen = str.length();
// if (otherLen == 0) {
// return this;
// }
// int len = value.length;
// char buf[] = Arrays.copyOf(value, len + otherLen);
// str.getChars(buf, len);
// return new String(buf, true);
// }
首先创建一个字符数组,长度是已有字符串和待拼接字符串的长度之和,再把两个字符串的值复制到新的字符数组中,
并用这个字符数组创建一个新的String对象并返回。
为了验证上面for循环中让使用StringBuilder,而不让使用+,编写以下代码并对比耗时
try(Cost cost = new Cost()){
String aa = "aa";
for (int i = 0; i < 100000; i++) {
aa+="bb";
}
}
try(Cost cost = new Cost()){
StringBuilder aa = new StringBuilder();
for (int i = 0; i < 100000; i++) {
aa.append("bb");
}
}
耗时输出结果如下
//cost:11565
//cost:1
注意这里的代码耗时统计的方式可以参考
Java实战-基于JDK的LRU算法实现、优雅的实现代码耗时统计(Spring AOP、AutoCloseable方式):
Java实战-基于JDK的LRU算法实现、优雅的实现代码耗时统计(Spring AOP、AutoCloseable方式)_霸道流氓气质的博客-CSDN博客
分析原因:
在for循环中,每次都是new了一个StringBuilder,然后再把String转成StringBuilder,再进行append。
而频繁的新建对象当然要耗费很多时间了,不仅仅会耗费时间,频繁的创建对象,还会造成内存资源的浪费。
为了验证以上原因,我们对使用+进行拼接字符串的代码进行反编译查看
总结:
经过对比,我们发现,直接使用StringBuilder的方式是效率最高的。
因为StringBuilder天生就是设计来定义可变字符串和字符串的变化操作的。
但是,还要强调的是:
1.如果不是在循环体中进行字符串拼接的话,直接使用+就好了。
2.如果在并发场景中进行字符串拼接的话,要使用StringBuffer来代替StringBuilder