基本类型转String
本文由 ImportNew - ImportNew读者 翻译自 java-performance。如需转载本文,请先参见文章末尾处的转载要求。
文章由 @邋遢爱好者 翻译, 并由ImportNew团队成员整理了全文。如果你也希望参与类似的系列文章翻译,可以加入我们的Java开发 和 技术翻译 小组。
通常我们需要把一些其它类型的值转换为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方法变复杂 了,你可以阅读这里。
如你所看到的,这样简单的重构就使splitting这个方法执行的时间得到了一个客观的变化。
split | split2 | split3 | |
Java 6 | 4.65 sec | 10.34 sec | 3.8 sec |
Java 7 | 6.72 sec | 8.29 sec | 4.37 sec |
原文链接: java-performance 翻译: ImportNew.com - ImportNew读者
译文链接: http://www.importnew.com/7550.html
[ 转载请保留原文出处、译者和译文链接。]