字符串是不可变的 – 这意味着我永远不应该使用+ =而且只能使用StringBuffer?

字符串是不可变的,这意味着,一旦创建它们就无法更改。

那么,这是否意味着如果你用+ =附加东西比你创建一个StringBuffer并附加文本那么需要更多的内存?

如果你使用+ =,每次必须保存在内存中时你会创建一个新的’对象’,不是吗?

是的,每次使用+ =创建一个新对象。 但这并不意味着它总是错误的做法。 这取决于您是否希望将该值作为字符串,或者您是否只是使用它来进一步构建字符串。

如果您确实希望x + y的结果作为字符串,那么您也可以使用字符串连接。 但是,如果你真的要(比方说)循环并附加另一个字符串,另一个字符串等 – 只需要将结果作为字符串放在最后,那么StringBuffer / StringBuilder就是你要走的路。 实际上,循环实际上是StringBuilder在字符串连接上得到的回报 – 5个甚至10个直接连接的性能差异将非常小,但是对于数千个,它变得更糟糕 – 主要是因为你得到O(N 2 )的复杂性串联与StringBuilder的O(N)复杂性。

在Java 5及更高版本中,你基本上应该使用StringBuilder – 它是不同步的,但这几乎总是好的; 想要在线程之间共享一个是非常罕见的。

我有一篇关于所有这些你可能会觉得有用的文章。

经验法则很简单:

如果在循环中运行连接,请不要使用+=

如果您没有在循环中运行连接,则使用+=无关紧要。 (除非性能关键应用程序

在Java 5或更高版本中,StringBuffer是线程安全的,因此除非您需要,否则您应该支付一些开销。 StringBuilder具有相同的API但不是线程安全的(即,您应该只在单个线程内部使用它)。

是的,如果要构建大型字符串,则使用StringBuilder会更有效。 作为API的一部分传递StringBuilder或StringBuffer可能是不值得的。 这太令人困惑了。

我同意上面发布的所有答案,但它会帮助您更多地了解Java的实现方式。 JVM在内部使用StringBuffers来编译String +运算符(来自StringBuffer Javadoc ):

编译器使用字符串缓冲区来实现二进制字符串连接运算符+。 例如,代码:

  x = "a" + 4 + "c" 

被编译为相当于:

  x = new StringBuffer().append("a").append(4).append("c") .toString() 

同样, x += "some new string"相当于x = x + "some new string" 。 你知道我要去哪儿吗?

如果你正在进行大量的字符串连接,使用StringBuffer会提高你的性能,但是如果你只是做了几个简单的字符串连接,Java编译器可能会为你优化它,你不会注意到它的差异。性能

是。 字符串是不可变的。 偶尔使用,+ =即可。 如果+ =操作密集,则应转向StringBuilder。

但是一旦没有对它们的引用,垃圾收集器将最终释放旧字符串

究竟。 如果线程安全不是问题,您应该使用StringBuilder。

作为旁注:可能有几个String对象使用相同的后缀char [] – 例如,每当使用substring()时,都不会创建新的char [],这使得使用它非常有效。

此外,编译器可能会为您做一些优化。 例如,如果你这样做

 static final String FOO = "foo"; static final String BAR = "bar"; String getFoobar() { return FOO + BAR; // no string concatenation at runtime } 

如果编译器在内部使用StringBuilder来尽可能优化字符串连接 – 如果不是将来可能的话,我也不会感到惊讶。

我认为它依赖于GC来收集废弃字符串的内存。 因此,如果对字符串操作进行大量操作,那么使用字符串构建器执行+ =肯定会更快。 但对大多数情况来说,这不应该是一个问题。

是的,你会这就是为什么你应该使用StringBuffer来连接很多字符串。

另请注意,从Java 5开始,您大多数时候也应该更喜欢StringBuilder。 它只是某种不同步的StringBuffer。

你是对的,Strings是不可变的,所以如果你在做大量的字符串连接时试图节省内存,你应该使用StringBuilder而不是+ =。

但是,你可能不介意。 程序是为人类读者编写的,因此您可以清晰明了。 如果您进行优化很重要,则应先进行分析。 除非你的程序非常重视字符串活动,否则可能会有其他瓶颈。

没有

它不会使用更多内存。 是的,创建了新对象,但旧对象被回收。 最后,使用的内存量是相同的。