1. 概述

在这个教程中,我们将探讨是否为了效率重用StringBuilder对象。我们将指导如何重用StringBuilder并解释其益处。

2. 优势

2.1. 优化对象创建

在Java中,由于字符串是不可变的,使用StringBuilder连接不同字符串通常可以避免不必要的对象创建。重用StringBuilder本身也可以避免额外的内存分配和垃圾回收开销。

2.2. 提高性能

StringBuilder对象是可变的,这使得我们可以在不创建新对象的情况下多次修改对象,显著提高了性能。

2.3. 减少内存使用

字符串对象是不可变的,这意味着它们在创建后不能被修改。当对字符串进行修改时,会创建新的对象,增加内存使用。通过使用StringBuilder实例,开发者可以避免不必要的对象创建,减少应用程序使用的内存量。

2.4. 改善缓存可靠性

每次应用程序创建新对象时,它可能在每次分配时位于不同的内存位置,导致缓存缺失,降低性能。通过重用StringBuilder实例,可以重复使用同一个对象,提高缓存利用率,从而提升性能。

3. 示例

在我们的第一个示例中,我们在每次循环迭代中创建一个新的StringBuilder对象:

for (int i = 0; i < 100; i++) {
    StringBuilder stringBuilder = new StringBuilder();
    stringBuilder.append("baeldung");
    stringBuilder.toString();
}

另一种方法是反复使用同一个StringBuilder对象。为此,我们需要在每次循环迭代的末尾调用delete()方法,删除StringBuilder中的整个字符数组:

StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < 100; i++) {
    stringBuilder.append("baeldung");
    stringBuilder.toString();
    stringBuilder.delete(0, stringBuilder.length());
}

而不用删除底层的字符数组,我们也可以在每次迭代后将StringBuilder的长度设为0:

StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < 100; i++) {
    stringBuilder.append("baeldung");
    stringBuilder.toString();
    stringBuilder.setLength(0);
}

让我们比较一下上述示例在简短基准测试中的差异:

Benchmark                                                   Mode  Cnt    Score    Error  Units
Example 1: new StringBuilder object                           ss   10  210,661 ± 15,237  ms/op
Example 2: reuse StringBuilder with delete()                  ss   10  185,908 ±  7,802  ms/op
Example 3: reuse StringBuilder with setLength()               ss   10  164,323 ±  1,909  ms/op

如预期,每次迭代的对象创建是最慢的。我们还可以看到,使用setLength(0)的方法比delete(0, stringBuilder.length())更快。这是因为通过setLength(),我们只改变了StringBuilder对象的计数字段的值,这个操作非常快。而delete()方法则需要StringBuilder对象删除指定范围的字符,这涉及到更复杂的数组移动操作。

在我们的例子中,通过传入0和最大长度,整个字符数组被删除。因此,使用setLength()方法通常更快地达到相同结果,因为数组的移动更复杂。

4. 何时重用StringBuilder

重要的是,并非所有字符串操作都需要StringBuilder。我们可以执行简单的操作,如无StringBuilder的字符串连接。也不必对所有操作都使用可重用的StringBuilder对于涉及大量操作或迭代次数的复杂字符串操作,我们应该使用可重用的StringBuilder

在并发应用中,我们也需要确保线程安全。如果没有适当的同步,多个线程可能会使用同一个StringBuilder对象,导致意外的行为。开发者可以通过同步方法或锁来防止竞争条件,确保线程安全。或者,类或线程可以在本地范围内仅重用StringBuilder对象。

有时,如果性能不是很重要,放弃重用StringBuilder和由此带来的性能提升也是有意义的,以确保代码易于理解和阅读

5. 总结

在这篇文章中,我们讨论了重用StringBuilder的优势,并给出了如何实现的具体示例。总的来说,重用StringBuilder有助于减少开销并提高性能。

如往常一样,示例代码可在GitHub上找到。