12

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

那么,这是否意味着如果使用 += 附加内容会比创建 StringBuffer 并将文本附加到其中需要更多的内存?

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

4

11 回答 11

25

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

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

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

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

于 2009-10-28T07:35:51.763 回答
7

经验法则很简单:

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

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

于 2009-10-28T07:37:23.540 回答
5

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

是的,如果您正在构建大字符串,使用 StringBuilder 会更有效。将 StringBuilder 或 StringBuffer 作为 API 的一部分传递可能不值得。这太令人费解了。

于 2009-10-28T07:35:15.693 回答
5

我同意上面发布的所有答案,但它会帮助您更多地了解 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 编译器可能会为你优化它,你不会注意到表现

于 2009-10-28T07:47:00.520 回答
3

是的。字符串是不可变的。对于偶尔使用,+= 是可以的。如果 += 操作很密集,你应该转向 StringBuilder。

于 2009-10-28T07:34:52.697 回答
1

确切地。如果线程安全不是问题,您应该使用 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 来优化字符串连接,我不会感到惊讶——如果将来还没有的话。

于 2009-10-28T07:35:08.843 回答
1

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

于 2009-10-28T07:35:15.053 回答
0

我认为它依靠 GC 来收集带有废弃字符串的内存。因此,如果您对字符串操作有很多操作,那么使用字符串生成器执行 += 肯定会更快。但在大多数情况下,这应该不是问题。

于 2009-10-28T07:35:05.480 回答
0

是的,你会的,这正是你应该使用 StringBuffer 连接很多字符串的原因。

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

于 2009-10-28T07:35:11.203 回答
0

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

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

于 2009-10-28T07:40:34.760 回答
0

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

于 2009-10-28T07:49:47.087 回答