12.6 字符串的性能
字符串对 Java 非常重要,其性能在其他章节也已经讨论过,这里再强调几点。
字符串保留
创建多个包含相同字符序列的字符串对象,这种情况很常见。没有必要在堆中为所有这些对象都分配空间;因为字符串是不可变的,所以重用现有的字符串往往更好。更多细节可参见第 7 章。
字符串编码
Java 的字符串采用的是 UTF-16 编码,而其他地方多是使用其他编码,所以将字符串编码到不同的字符集的操作很常见。对于 Charset 类的 encode() 和 decode() 方法而言,如果一次只处理一个或几个字符,它们会非常慢;务必完整缓存一些数据,再进行处理,本章前面也讨论过。
网络编码
在编码静态字符串(来自 JSP 文件等地方)时,Java EE 应用服务器往往会特殊处理;更多细节可参见第 10 章。
字符串连接是另一个可能会出现性能问题的地方。考虑这样一个简单的字符串连接操作:
String answer = integerPart + "." + mantissa;
这行代码实际上非常高效;javac 编译器的语法糖会将其转换为如下代码:
String answer = new StringBuilder(integerPart).append(".").append(mantissa).toString();
不过问题来了,如果这个字符串是逐步构造起来的:
String answer = integerPart;answer +=".";answer += mantissa;
那么这段代码就会被翻译为:
String answer = new StringBuilder(integerPart).toString();answer = new StringBuilder(answer).append(".").toString();answer = new StringBuilder(answer).append(mantissa).toString();
所有那些临时的 StringBuilder 对象和中间的 String 对象都很低效。永远不要使用连接来构造字符串,除非能在逻辑意义上的一行代码内完成;也不要在循环内使用字符串连接,除非连接后的字符串不会用于下一次循环迭代。对于其他情况,应该总是使用 StringBuilder,以获得更好的性能。在第 1 章中我曾经说过,某种情况下“过早的优化”只是表示要“编写良好的代码”。这就是最好的例子。
快速小结
1. 一行的字符串连接代码性能很不错。
2. 对于多行的连接操作,一定要确保使用
StringBuilder。
快速小结