当前位置:文档之家› String字符串拼接对性能地影响

String字符串拼接对性能地影响

String、StringBuffer & StringBuilder字符串拼接对性能的影响Author:苏康福date:2013-3-11 1.StringString字符串是常量;它们的值在创建之后不能更改。

String类包括的方法可用于检查序列的单个字符、比较字符串、搜索字符串、提取子字符串、创建字符串副本并将所有字符全部转换为大写或小写。

Java 语言提供对字符串串联符号("+")以及将其他对象转换为字符串的特殊支持。

字符串串联是通过StringBuilder(或StringBuffer)类及其append方法实现的。

字符串转换是通过toString方法实现的,该方法由Object类定义,并可被Java 中的所有类继承。

《JDK6》String 类中每一个看起来会修改字符串值的方法,实际上都是创建一个全新的String 对象,以包含修改后的字符串内容。

《Java Thinking》String对象是不可变的,具有只读特性,指向它的任何引用都不可能改变它的值。

String a = “Kangfu”;String b = a ;b += “Su”;String c = a.toUpperCase();a、b、c各指向不同的对象。

String的重载操作符“+”和“+=”,可以用来链接字符串。

见实验方法一。

2.StringBufferStringBuffer,线程安全的可变字符序列。

可将字符串缓冲区安全地用于多个线程。

可以在必要时对这些方法进行同步,因此任意特定实例上的所有操作就好像是以串行顺序发生的,该顺序与所涉及的每个线程进行的方法调用顺序一致。

从JDK 5 开始,为该类补充了一个单个线程使用的等价类,即StringBuilder。

与该类相比,通常应该优先使用StringBuilder类,因为它支持所有相同的操作,但由于它不执行同步,所以速度更快。

《JDK6》3.StringBuilderStringBuilder,一个可变的字符序列。

此类提供一个与StringBuffer兼容的API,但不保证同步。

该类被设计用作StringBuffer的一个简易替换,用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)。

如果可能,建议优先采用该类,因为在大多数实现中,它比StringBuffer要快。

StringBuilder 允许预先指定大小。

如果知道最终字符串大概长度,那预先指定StingBuilder的大小可以避免多次重新分配缓冲。

《JDK6》4.实例分析定义Java类(见string/test/StringConcatenation.java)1)方法一源码:Jvm字节码:从字节码可看出,类似这种情况的定义,java编译器直接把拼接表达式看成单个String 变量。

2)方法二源码:Jvm字节码:从字节码中可看出,类似这种情况的定义(String变量的定义中带有其他对象参数表达式),java编译器自动创建了一个StringBuilder变量来构造结果。

3)方法三源码:Jvm字节码:从字节码中可看出,循环体从第9行开始到38行结束,每次运行result += "SELECT"; 都会new StringBuilder()一次,过程中产生大量需要垃圾回收的中间对象。

4)方法四源码:Jvm字节码:从字节码中可看出,循环体从第14行开始到30行结束,循环体内直接调用append 方法即可,代码干净整洁,效率也高。

四个方法运行结果,见下图。

根据运行环境不同,时间也可能不同。

但是大概能看出第三个方法运行结果比较糟糕。

(两个循环次数为1000结果图)(两个循环次数为10000结果图)5.结论通过如上4个例子,得出结论:➢如果字符串拼接操作比较简单(类似方法一、二),那采用String+操作符或StringBuilder的append方法,对性能影响不明显,使用哪种方式根据具体情形而定。

类似方法一(或者+更少)的情况使用String+操作符更简洁,类似方法二使用StringBuilder拼接会更优。

➢如果在循环中使用字符串拼接(类似方法三、四),那最好先创建一个StringBuilder 对象,用来构造最终结果,循环体中调用其append方法进行拼接,这样效率会快很多。

➢总之,在追求性能的同时也要追求代码的简洁美观和可读性。

6.附录string/test/StringConcatenation.java:package test;import java.util.HashMap;import java.util.Map;public class StringConcatenation {//无参数使用String+拼接字符串public String getString(){String result = "SELECT ID,NAME,CARDID, AGE"+ "FROM USERINFO "+ "WHERE NAME LIKE '%苏%' "+ "AND AGE > 25 "+ "ORDER BY AGE ASC";return result;}//带参数使用String+拼接字符串public String getString(String name, int age){String result = "SELECT ID,NAME,CARDID, TRUNC(BORNEDDATE)"+ "FROM USERINFO "+ "WHERE NAME LIKE '%" + name + "%' "+ "AND AGE > " + age+ " ORDER BY AGE ASC";return result;}//在循环中使用String+拼接字符串public String implicit(){String result = "";for(int i=0; i<10000; i++){result += "SELECT";}return result;}//在循环中使用StringBuilder拼接字符串public String explicit(){StringBuilder result = new StringBuilder();for(int i=0; i<10000; i++){result.append("SELECT");}return result.toString();}//各方法运行时间public static void main(String[] args){StringConcatenation sc = new StringConcatenation();long time1 = 0L, time2 = 0L;Map<String, Object> map = new HashMap<String, Object>();System.out.println("无参数使用String+拼接字符串...");time1 = System.currentTimeMillis();map.put("string1", sc.getString());time2 = System.currentTimeMillis();System.out.println("运行时间:" + (time2 - time1) + " ms\n\n");System.out.println("带参数使用String+拼接字符串...");time1 = System.currentTimeMillis();map.put("string2", sc.getString("苏", 25));time2 = System.currentTimeMillis();System.out.println("运行时间:" + (time2 - time1) + " ms\n\n");System.out.println("在循环中使用String+拼接字符串...");time1 = System.currentTimeMillis();map.put("string3", sc.implicit());time2 = System.currentTimeMillis();实用标准文案精彩文档System.out.println("运行时间:" + (time2 - time1) + " ms\n\n");System.out.println("在循环中使用StringBuilder拼接字符串..."); time1 = System.currentTimeMillis();map.put("string4", sc.explicit());time2 = System.currentTimeMillis();System.out.println("运行时间:" + (time2 - time1) + " ms");} }。

相关主题