背景:
最近项目中需要用到服务器模板和字符串拼接技术。服务器模板技术很多,JSP、Velocity、JDynamiTe等很多。字符串拼接技术在Java中更简单,StringBuilder、StringBuffer和重载的字符串“+”操作。但是实际开发中,发现自己平时对Java的字符串拼接的细节处理真的很差。
基础:
字符串操作主要问题在效率上,包括如下两点:
(1)拼接效率。
(2)查找、回溯效率。
凡是了解Java的都知道下面3点,而且这肯定是Java面试时必考的。
(1)StringBuilder是线程安全的;
(2)StringBuffer是线程不安全的;
(3)Java的String是final的,而且Java的String对象是放在字符串常量池的。
其实在这之前,我对这几点也只是“知其然而不知其所以然”,因为懒惰的关系,这三个类的源码也没看过,今天终于有时间看了下,顺便总结下。
继承体系
这个三个类的继承体系如下:
(1)他们都实现了CharSequence接口,而且都是可以被序列化、被比较大小的。
(2)阅读它们的源码可以知道,他们在管理字符串时,都使用的char数组。其实字符串本身就是一种数据结构,和Stack、Queue一样,只是String数据结构太常见了,才导致我们已经不把它当成一种数据结构了。
(3)StringBuilder和StringBuffer有一个共同的抽象父类AbstractStringBuilder,凡是对StringBuilder的方法调用,在StringBuilder内部都是调用的super方法,StringBuffer也一样,只不过StringBuffer在自己的方法上加上了synchronized关键字。
append方法
我们对StringBuilder和StringBuffer调用最多的应该就是append方法了,append方法有很多重载方法,这些重载方法的实现思路都是一样的,首先把传入的参数转换为char数组,然后把char数组和自己本身的数组进行合并,至于合并算法就很简单了(不过可以注意下合并后char数组的长度)。
不同类型的参数转换为char数组的方式略有不同,Object类型调用String的静态方法valueOf,基本类型的除了char和boolean外,都是调用的他们类型本身的getChars静态方法。char添加比其他类型略快,不用调用getChars方法,boolean则直接添加一个[‘t’,’r’,’u’,’e’]或者[‘f’,’a’,’l’,’s’,’e’]字符数组。
所以从上面可以看出,调用append方法的时候如果可以直接append一个char或者char数组是最好的。
String
接着说下String,我们都知道JVM本身是对String对象有过优化的,而且实现了对String的操作符(+)的重载。JVM把String对象都放在常量池中,每次new对象的时候,都先去检查常量池存不存在一个相同的字符串序列,如果存在序列相同的就返回这个对象,如果不存在则创建一个新的。
有一个不负责任的笼统说法:JVM对String + 的重载其实是在编译阶段把+ 翻译成了StringBuilder(JDK 1.4前是StringBuffer)。
比如:
String s = “a”; String m = s + “a” + “d”;
编译后就是:
String s =”a”; String m = (new StringBuilder(s)).append(“a”).append(“d”).toString();
所以,根据这个规律我们在for循环中使用+操作效率是比较低的。
当然上面的情况是有特例的,毕竟Java编译机制不会这么简单,比如当Java编译器在编译时能确定字符串的值时就不会遵循上面的编译规则。
String s= “a”; String m = “s” + “x” + “e”;
总结:
在构造StringBuilder的时候能确定序列长度,最好指定序列长度,这样能减少append时的数组copy。
在使用StringBuilder的时候如果可以尽量使用append字符的方式,如:append(‘a’)比append(“a”)要好,而且不会产生字符串a的对象。但是也不要特意这样,比如append(‘a’).append(‘b’).append(‘c’)替代append(“abc”),那就有点画蛇添足了。
其次,在append的参数中少用字符串+操作,如果大量的使用字符串+操作有的时候会失去使用StringBuilder的意义。比如
append(“a”+s+”d”);
应该拆分为
append(‘a’).append(s).append(‘d’);
这样在大量循环中,能帮我们提高效率。
最后,关于字符串的查找和回溯操作,如果可以,我们可以直接使用索引的方式去截取字符串也就是操作String类的API,这比在Java中使用正则表达式要好很多。
JavaString、StringBuilder、StringBuffer总结
原文地址:http://blog.csdn.net/hackersaillen/article/details/46299871