通常我们需要把一些其它类型的值转换为String,这些类型可能就包括基本类型。如果你有2个甚至更多的基本类型变量位于字符串连接的开头处,那么你需要显示地把他们转换为String(否则 System.out.println(1+ ‘a’) 将打印98而不 是’la’).当然.你也可以使用String.valueOf方法(或者其他包装类的方法)


把一个字面量为空的字符串与一个基本类型的变量串连起来(在我们的示例中,”"+1)是最简单的方式,这个表达式的值就是一个字符串,你可以很安全地把任何基本类型值连接在后面—-编译器会很小心隐式地把他们转换成String。


不幸的是,这是能想象的最糟糕的方式,为了理解为什么是这样,我们需要查看下String连接操作在java中是被怎样运作的。 假如有一个String值(字面值、变量或方法的返回值) 后面跟随“+”这个操作符,再后面跟个其他任何表达式


String_exp + any_exp


java 编译器将会翻译成:


new StringBuilder().append(String_exp).append(any_exp).toString();


StringBuilder(String) 构造函数分配一个包含16个字符的缓冲,所以追加最多16个字符的StringBuilder不需要重新分配缓冲,但追加超过16个字符的将需要扩展缓冲。最后,StringBuilder.toString()方法中将会利用StringBuilder的缓冲拷贝一个新的String对象返回。


意味着一个单独的基本类型值转换为String的最坏一种情况是:你需要这样分配:一个StringBuilder,一个长度为16的char数组char[16],一个String和一个适合大小的char数组,用String.valueOf方法至少可以避免创建一个 StringBuilder。


有时你实际完全不需要把基本类型转换为String,例如:你解析一个被逗号符分割的String,最初的版本你可能会这样写


final int nextComma = str.indexOf("'");


甚至这样


final int nextComma = str.indexOf('\'');#注:反斜杠后面是两个单引号


之后程序可能需要扩展至支持任何分隔符,当然支持任何分隔符意味着你需要一个Stirng对象的分隔符并且使用String.indexof(String)方法.我们建议把一个默认的分隔符存储在m_separator 这变量中,代码看起来像这个:


private static List<String> split( final String str )

{

final List<String> res = new ArrayList<String>( 10 );

int pos, prev = 0;

while ( ( pos = str.indexOf( m_separator, prev ) ) != -1 )

{

res.add( str.substring( prev, pos ) );

prev = pos + m_separator.length(); // start from next char after separator

}

res.add( str.substring( prev ) );

return res;

}


但是后来你发现使用的分隔符从来就没有超过一个字符,在初始化时,你会定义一个char类型m_separtor来替换String类型的m_separtor并且适当的改变它的setter方法。但你又不想大量的改动解析方法(为什么我们如果改变这工作的代码呢?):


private static List<String> split2( final String str )

{

final List<String> res = new ArrayList<String>( 10 );

int pos, prev = 0;

while ( ( pos = str.indexOf("" + m_separatorChar, prev ) ) != -1 )

{

res.add( str.substring( prev, pos ) );

prev = pos + 1; // start from next char after separator

}

res.add( str.substring( prev ) );

return res;

}


如你所看到的,indexOf方法被更改了。但是它还是创建了一个字符串并且可用,当然这样并不对,因为String API中本来就有一个重载的indexOf方法,它可以接受char类型的参数,我们改动下:


private static List<String> split3( final String str )

{

final List<String> res = new ArrayList<String>( 10 );

int pos, prev = 0;

while ( ( pos = str.indexOf( m_separatorChar, prev ) ) != -1 )

{

res.add( str.substring( prev, pos ) );

prev = pos + 1; // start from next char after separator

}

res.add( str.substring( prev ) );

return res;

}


测试如下, “abc,def,ghi,jkl,mno,pqr,stu,vwx,yz” 这个字符串用这3种方法分别简析10次,下面是java 6_41 和 7_15的运行时间,java7的运行时间增加是因为String.subString方法变复杂 了,你可以阅读这里


http://java-performance.info/changes-to-string-java-1-7-0_06/


如你所看到的,这样简单的重构就使splitting这个方法执行的时间得到了一个客观的变化。



splitsplit2split3
Java 64.65 sec10.34 sec3.8 sec
Java 76.72 sec8.29 sec4.37 sec