我正在阅读“更好,更快,更轻松的Java ”(由Bruce Tate和Justin Gehtland撰写)并且熟悉敏捷类型团队的可读性要求,例如Robert Martin在他的讨论中所讨论的内容清洁编码书。在我现在的团队中,我被告知明确不要使用+
运算符,因为它会在运行时创建额外的(和不必要的)字符串对象。
但是这个article,写在'04讨论对象分配是关于10个机器指令。 (基本上是免费的)
它还讨论了GC如何帮助降低此环境中的成本。
使用+
,StringBuilder
或StringBuffer
之间的实际性能权衡是什么? (在我的例子中,它仅为StringBuffer
,因为我们仅限于Java 1.4.2。)
StringBuffer
对我来说导致丑陋,不太可读的代码,正如Tate的书中的几个例子所示。并且StringBuffer
是线程同步的,它似乎有自己的成本超过使用+
运算符的“危险”。
思想/意见?
答案 0 :(得分:47)
编译器将String
连接转换为StringBuilder
操作。
要了解编译器的工作方式,我将采用一个示例类,编译它并使用jad对其进行反编译,以查看生成的字节码是什么。
原班级:
public void method1() {
System.out.println("The answer is: " + 42);
}
public void method2(int value) {
System.out.println("The answer is: " + value);
}
public void method3(int value) {
String a = "The answer is: " + value;
System.out.println(a + " what is the question ?");
}
反编译类:
public void method1()
{
System.out.println("The answer is: 42");
}
public void method2(int value)
{
System.out.println((new StringBuilder("The answer is: ")).append(value).toString());
}
public void method3(int value)
{
String a = (new StringBuilder("The answer is: ")).append(value).toString();
System.out.println((new StringBuilder(String.valueOf(a))).append(" what is the question ?").toString());
}
method1
上,编译器在编译时执行了该操作。method2
String
级联相当于手动使用StringBuilder
。method3
上,String
连接肯定是错误的,因为编译器正在创建第二个StringBuilder
而不是重用前一个{.1}。所以我的简单规则是连接是好的,除非你需要再次连接结果:例如在循环中或当你需要存储中间结果时。
答案 1 :(得分:21)
您的团队需要了解reasons for avoiding repeated string concatenation。
当使用StringBuffer
时,确实 次 - 特别是当你在循环中创建一个字符串时,特别是如果你不是确定< / em>循环中会有很少的迭代。请注意,这不仅仅是创建新对象的问题 - 而是复制已经附加的所有文本数据。还要记住,如果不考虑垃圾收集,对象分配只是“基本上免费”。是的,如果当前一代有足够的空间,那基本上就是增加一个指针......但是:
所有这些东西都是相当便宜因为它“通常”不值得将设计从优雅中剔除以避免创建对象......但你不应该将它们视为免费
另一方面,在不需要中间字符串的情况下使用StringBuffer
没有意义。例如:
String x = a + b + c + d;
至少和以下一样有效:
StringBuffer buffer = new StringBuffer();
buffer.append(a);
buffer.append(b);
buffer.append(c);
buffer.append(d);
String x = buffer.toString();
答案 2 :(得分:5)
对于小型连接,您可以简单地使用String和+以便于阅读。性能不会受到影响。但是如果你正在进行大量的连接操作,那就去StringBuffer。
答案 3 :(得分:0)
其他答案提到在循环中创建字符串时应使用StringBuilder
。但是,大多数循环都是遍历集合,而从Java 8可以使用joining
类中的Collectors
方法将集合转换为字符串。
作为示例,在下面的代码中:
String result = Arrays.asList("Apple", "Banana", "Orange").stream()
.collect(Collectors.joining(", ", "<", ">"));
result
将是:<Apple, Banana, Orange>