震惊!字符串连接竟然有这么多方法
在《阿里巴巴 Java 开发手册》的OOP规约第17条指出:在循环体内,字符串的连接方式,使用 StringBuilder 的 append 方法而不是 " + "。具体如下:
【推荐】循环体内,字符串的连接方式,使用 StringBuilder 的 append 方法进行扩展。
反例: String chenmo = "沉默"; String wanger = "王二"; String sum=chenmo+wanger;
上面的代码反编译:
String chenmo = "\u6C89\u9ED8"; // 沉默 String wanger = "\u738B\u4E8C"; // 王二 String sum=(newStringBuilder(String.valueOf(chenmo))).append(wanger).toString();
通过反编译可得知:反编译出的字节码文件显示在使用"+"进行字符串连接时,每次都会 new 出一个 StringBuilder 对象,然后进行append 操作,最后通过 toString 方法返回 String 对象,这样不但使时间消耗增加,还造成内存资源浪费。
在java中,连接字符串常用的方式有以下几种:
1.直接用“+”号
2.使用String的方法concat
3.使用StringBuilder的append
4.使用StringBuffer的append
为了测试四种方法的性能,使用长度为10万的字符串进行测试。
输入一个长度为100000的字符串,然后for循环每次取出长度为1的子串,添加到新字符串str1的末尾。测试代码如下:
(只保留核心代码)
public class 连接字符串 { public static void main(String[] args) { Scanner sc = new Scanner(System.in); String str = sc.next(); /*使用"+"连接*/ String str1 = ""; for (int i = 0; i < str.length(); i++) { str1 += str.substring(i, 1 + i); } /*StringBuilder的append方法连接*/ StringBuilder str1 = new StringBuilder(); long start = System.currentTimeMillis(); for (int i = 0; i < str.length(); i++) { str1.append(str.substring(i, 1 + i)); } /*使用String的concat方法连接*/ String str1 = ""; for (int i = 0; i < str.length(); i++) { str1 = str1.concat(String.valueOf(str.substring(i, 1 + i))); } /*StringBuffer的append方法连接*/ StringBuffer str1 = new StringBuffer(); for (int i = 0; i < str.length(); i++) { str1.append(str.substring(i, 1 + i)); } } }
测试结果:
1.直接用“+”号
2.使用String的方法concat
3.使用StringBuffer的append
4.使用StringBuilder的append
根据上面的分析和测试可以知道:
- Java 中字符串拼接不要直接使用+拼接。
- 在不需要考虑线程安全问题的时候,使用StringBuilder的效率比StringBuffer更高
注:StringUtils.join也可以用于字符串拼接,因为用的较少,所以未进行比较,据说性能与StringBuffer的append方法相差无几,比其要好。
关于 String 的其他最佳实践
使用str != null && str.length() != 0来判断空串,效率比较高。
在需要把其他对象转换为字符串对象时,使用String.valueOf(obj)而不是直接调用obj.toString()方法,因为前者已经对空值进行检测了,不会抛出空指针异常。
使用String.format()方法对字符串进行格式化输出。
对于较多的比较,使用switch代替if - else。(在 JDK 7 及以上版本,可以在switch结构中使用字符串了)