Java 程序优化:字符串操作、基本运算方法等优化策略(一)
摘抄自:http://www.ibm.com/developerworks/cn/java/j-lo-basic-types/index.html#ibm-pcon
一、字符串是什么
1.字符串对象或其等价对象(如char数组),在内存中总是占据最大的空间快
2.String和char数组
char数组 + 偏移量 + 长度 = String
3.String三个基本特点
- 不变性:一旦定义,不能改变
- 针对常量池的优化:当两个String对象有相同的值,则只引用常量池的同一个拷贝
- 类的final定义
清单 1. 示例代码
1 public class StringDemo { 2 public static void main(String[] args){ 3 String str1 = "abc"; 4 String str2 = "abc"; 5 String str3 = new String("abc"); 6 String str4 = str1; 7 // str1、str2、str4 引用了相同的地址,但是 str3 却重新开辟了一块内存空间, 8 // 虽然 str3 单独占用了堆空间,但是它所指向的实体和 str1 完全一样 9 System.out.println(str1==str2); //true 10 System.out.println(str1==str3); //false 11 System.out.println(str1.intern()==str3.intern()); //true 12 System.out.println(str1==str4); //true 13 System.out.println(str2==str4); //true 14 System.out.println(str4.intern()==str3.intern()); //true 15 } 16 }
二、 切分字符串方式讨论
- split 方法支持传入正则表达式帮助处理字符串,操作较为简单,但是缺点是它所依赖的算法在对简单的字符串分割时性能较差。
- StringTokenizer 类通过它的 nextToken() 方法便可以得到下一个分割的字符串,通过 hasMoreToken 方法可以知道是否有更多的字符串需要处理。
对比发现 split 的耗时非常的长,采用 StringTokenizer 对象处理速度很快。
- 自己实现字符串分割算法,使用 substring 方法和 indexOf 方法组合而成的字符串分割算法可以帮助很快切分字符串并替换内容。
三、合并对象
String对象不可变,进行字符串拼接、修改时,会生成新的对象,性能差
但是JVM会对 A+B+C+D这种拼接优化,只会产生一个最终的新的字符串
String 对象连接、使用 concat 方法连接、使用 StringBuilder 类等多种方式
1 public static void main(String[] args) { 2 // TODO Auto-generated method stub 3 String str = null; 4 String result = ""; 5 long start = System.currentTimeMillis(); 6 for (int i = 0; i < 10000; i++) { 7 str = str + i; 8 } //第一种方法编译器判断 String 的加法运行成 StringBuilder 实现 9 long end = System.currentTimeMillis();//但是编译器没有做出足够聪明的判断,每次循环都生成了新的 StringBuilder 实例从而大大降低了系统性能。 10 System.out.println(end - start); //时间最长 11 start = System.currentTimeMillis(); 12 for (int i = 0; i < 10000; i++) { 13 result = result.concat(String.valueOf(i)); 14 } 15 end = System.currentTimeMillis(); 16 System.out.println(end - start); //时间次长 17 start = System.currentTimeMillis(); 18 StringBuilder sb = new StringBuilder(); 19 for (int i = 0; i < 10000; i++) { 20 sb.append(i); 21 } 22 end = System.currentTimeMillis(); 23 System.out.println(end - start); //时间最短 24 }
StringBuffer 几乎所有方法都做了同步,能保证线程安全,但消耗了一定的系统资源
StringBuilder 反之,不同步,不安全,效率搞高
扩充策略
将原有的容量大小翻倍,以新的容量申请内存空间,建立新的 char 数组,然后将原数组中的内容复制到这个新的数组中。因此,对于大对象的扩容会涉及大量的内存复制操作。如果能够预先评估大小,会提高性能。
四、字符串的比较
for any two strings s and t, s.intern() == t.intern() is true if and only if s.equals(t) is true.
str1.equals(str2)为true 当且仅当str1.intern() == str2.intern()为true