Tips
书中的源代码地址: https://github.com/jbloch/effective-java-3e-source-code
注意, 书中的有些代码里方法是基于 Java 9 API 中的, 所以 JDK 最好下载 JDK 9 以上的版本.
Effective Java, Third Edition
63. 注意字符串连接的性能
字符串连接操作符 (+) 是将几个字符串组合成一个字符串的便捷的方法. 对于生成单行输出或构造一个小的, 固定大小的对象的字符串表示形式, 它是可以的, 但是它不能伸缩. 重复使用字符串连接运算符来连接 n 个字符串需要 n 的平方级的时间. 这是由于字符串是不可变的这一事实导致的结果(条目 17). 当连接两个字符串时, 需要复制这两个字符串的内容.
例如, 考虑这个方法, 它通过为每个项目重复连接一行来构造账单语句的字符串表示:
- // Inappropriate use of string concatenation - Performs poorly!
- public String statement() {
- String result = "";
- for (int i = 0; i < numItems(); i++)
- result += lineForItem(i); // String concatenation
- return result;
- }
如果项的数量很大, 则该方法的性能非常糟糕. 为了达到可接受的性能, 使用 StringBuilder 代替 String 来存储正在构建的语句:
- public String statement() {
- StringBuilder b = new StringBuilder(numItems() * LINE_WIDTH);
- for (int i = 0; i < numItems(); i++)
- b.append(lineForItem(i));
- return b.toString();
- }
自 Java 6 以来, 为了使字符串连接更快, 已经做了大量工作, 但是这两个方法在性能上的差异仍然很大: 如果 numItems 返回 100 个元素, 每个 lineForItem 返回一个固定长度为 80 个字符串, 那么在我的机器上运行, 第二个方法的速度是第一个方法的 6.5 倍. 由于第一种方法在项目数量上是平方级增长的, 而第二种方法是线性的, 所以随着项目数量的增加, 性能差异会变得越来越大. 注意, 第二个方法预先分配了一个足够大的 StringBuilder 来保存整个结果, 从而消除了自动增长的需要. 即使使用默认大小的 StringBuilder, 它仍然比第一个方法快 5.5 倍.
道理很简单: 除非性能无关紧要, 否则不要使用字符串连接操作符组合多个字符串. 而是使用 StringBuilder 的 append 方法. 或者, 使用字符数组, 或者一次处理一个字符串, 而不是把它们组合起来.
来源: http://www.jianshu.com/p/29ce30d4d683