String StringBuffer StringBuilder应该算是最常用的几个类型了。什么场景下用什么,对于java码农来说应该是轻车熟路的事了,写代码测试一下:
首先复习一下这三种类型适用场景: String适用于经常要用到的字符串,或者定义以后不会改变的字符串(
String是final类型的),StringBuffer适用于需要经常拼接的字符串,如xml转String时,或者拼接sql时,都常用到StringBuffer。StringBuilder和StringBuffer类似,不过StringBuffer是线程安全的,StringBuilder是线程不安全的,单线程的情况下尽量用StringBuilder吧。
测试用例:
首先,100万个循环测试。 对于String,测试三种场景: 在循环内定义变量,并且每次循环相加的字符串都跟上次循环不同;在循环内定义变量,每次相加的字符串跟上次相同;在循环外定义,每次相加字符串跟上次循环相同。
对于StringBuffer和StringBuilder,一样的场景,只是没有循环外定义了(刚开始很2得也进行了循环外定义,但是后来发现程序卡死了,然后发现StringBuffer循环外定义,字符串会越来越大,最终把内存耗死。。。)
代码:
package otherTest; /** * StringTest : * @author xuejupo [email protected] * create in 2015-11-28 下午11:50:43 */ public class StringTest { private static int max = 1000000; /** * main: * @param args * void 返回类型 */ public static void main(String[] args) { // TODO Auto-generated method stub long start = System.currentTimeMillis(); f1(); long end1 = System.currentTimeMillis(); System.out.println("String 类型,在循环内定义,并且循环时字符串定义都不相同耗时:\t"+(end1 - start)); f11(); long end2 = System.currentTimeMillis(); System.out.println("String 类型,在循环内定义,并且循环时所有字符串定义都相同耗时:\t"+(end2 - end1)); f2(); long end3 = System.currentTimeMillis(); System.out.println("String 类型,在循环外定义,并且循环时所有字符串定义都相同耗时:\t"+(end3 - end2)); f3(); long end4 = System.currentTimeMillis(); System.out.println("StringBuffer 类型,在循环内定义,并且循环时字符串定义都不相同耗时:\t"+(end4 - end3)); f31(); long end5 = System.currentTimeMillis(); System.out.println("StringBuffer 类型,在循环内定义,并且循环时所有字符串定义都相同耗时:\t"+(end5 - end4)); // f4(); long end6 = System.currentTimeMillis(); // System.out.println("StringBuffer 类型,在循环外定义,并且循环时所有字符串定义都相同耗时:\t"+(end6 - end5)); f5(); long end7 = System.currentTimeMillis(); System.out.println("StringBuilder 类型,在循环内定义,并且循环时字符串定义都相同耗时:\t"+(end7 - end6)); f51(); long end8 = System.currentTimeMillis(); System.out.println("StringBuilder 类型,在循环内定义,并且循环时所有字符串定义不都相同耗时:\t"+(end8 - end7)); // f6(); long end9 = System.currentTimeMillis(); // System.out.println("StringBuilder 类型,在循环外定义,并且循环时所有字符串定义都相同耗时:\t"+(end9 - end8)); } private static void f1(){ for(int i = 0; i < max; i ++){ String s1 = "abc"+i; String s2 = "def"+i; String s3 = "def2"+i; String s4 = "def3"+i; String s5 = s1 + s2 + s3 + s4; } } private static void f11(){ for(int i = 0; i < max; i ++){ String s1 = "abc"; String s2 = "def"; String s3 = "def2"; String s4 = "def3"; String s5 = s1 + s2 + s3 + s4; } } private static void f2(){ String s1 = "abc"; String s2 = "def"; String s3 = "def2"; String s4 = "def3"; String s5 = null; for(int i = 0; i < max; i ++){ s5 = s1 + s2 + s3 + s4; } } private static void f31(){ for(int i = 0; i < max; i ++){ StringBuffer s1 = new StringBuffer("abc"); s1.append("def"); s1.append("def2"); s1.append("def3"); s1.toString(); } } private static void f3(){ for(int i = 0; i < max; i ++){ StringBuffer s1 = new StringBuffer("abc"+i); s1.append("def"+i); s1.append("def2"+i); s1.append("def3"+i); s1.toString(); } } // private static void f4(){ // StringBuffer s1 = new StringBuffer(); // for(int i = 0; i < max; i ++){ // s1.append("abc"); // s1.append("def"); // s1.append("def2"); // s1.append("def3"); // s1.toString(); // } // } private static void f5(){ for(int i = 0; i < max; i ++){ StringBuilder s1 = new StringBuilder(); s1.append("abc"); s1.append("def"); s1.append("def2"); s1.append("def3"); s1.toString(); } } private static void f51(){ for(int i = 0; i < max; i ++){ StringBuilder s1 = new StringBuilder(); s1.append("abc"+i); s1.append("def"+i); s1.append("def2"+i); s1.append("def3"+i); s1.toString(); } } // private static void f6(){ // StringBuilder s1 = new StringBuilder(); // for(int i = 0; i < max; i ++){ // s1.append("abc"); // s1.append("def"); // s1.append("def2"); // s1.append("def3"); // s1.toString(); // } // } }
结果:
String 类型,在循环内定义,并且循环时字符串定义都不相同耗时: 609 String 类型,在循环内定义,并且循环时所有字符串定义都相同耗时: 90 String 类型,在循环外定义,并且循环时所有字符串定义都相同耗时: 90 StringBuffer 类型,在循环内定义,并且循环时字符串定义都不相同耗时: 495 StringBuffer 类型,在循环内定义,并且循环时所有字符串定义都相同耗时: 156 StringBuilder 类型,在循环内定义,并且循环时字符串定义都相同耗时: 86 StringBuilder 类型,在循环内定义,并且循环时所有字符串定义不都相同耗时: 470
分析一下: 从结果可以看到,对于在循环内String类型的相加,如果每次相加的字符串都定义过,那么String类型的相加其实是不比StringBuffer性能差的。jvm对String类型肯定做过充分的优化,所以每次循环相加相同的字符串耗时要比相加不同的字符串耗时少很多。StringBuilder相对来说比StringBuffer性能好一些,并且会优于优化后的String,单线程情况下尽量用StringBuilder吧。