String Builders

StringBuilder 类

字符串对象类似于StringBuilder对象,区别在于它们可以被修改。在内部,这些对象被视为包含字符序列的可变长度数组。在任何时候,都可以通过方法调用改变序列的长度和内容。
除非String Builder能带来更简洁的代码(参见本节末尾的示例程序)或更优的性能,否则应始终使用字符串。在Java SE 9之前,若需连接大量字符串,向StringBuilder对象追加内容可能更高效。Java SE 9中已优化字符串连接操作,使其效率超越StringBuilder的追加方式。

长度和容量

StringBuilder 类与 String 类类似,都提供了一个 length() 方法,该方法返回构建器中字符序列的长度。
与字符串不同,每个String Builder都具有容量,即已分配的字符空间数量。该容量由 capacity() 方法返回,始终大于或等于长度(通常更大),并会根据需要自动扩展以容纳String Builder中的新增内容。

您可以使用 StringBuilder 类的以下构造函数:

  • StringBuilder():创建一个容量为16(16个空元素)的String Builder。
  • StringBuilder(CharSequence cs):构造一个String Builder,其包含与指定CharSequence相同的字符,并在CharSequence之后附加16个空元素。
  • StringBuilder(int initCapacity):创建一个具有指定初始容量的空String Builder。
  • StringBuilder(String s):创建一个String Builder,其值由指定字符串初始化,并在字符串末尾附加16个空元素。

举个例子,下面的代码:

// creates empty builder, capacity 16
StringBuilder sb = new StringBuilder();
// adds 9 character string at beginning
sb.append("Greetings");

将生成一个长度为9、容量为16的字符串构建器:
Length and capacity of a `StringBuilder`

StringBuilder 类提供了一些与长度和容量相关的、String 类所不具备的方法:

  • void setLength(int newLength): 设置字符序列的长度。若 newLength 小于 length() 返回值,则截断字符序列末尾的字符;若 newLength 大于 length() 返回值,则在字符序列末尾添加 null 字符。
  • void ensureCapacity(int minCapacity): 确保容量至少等于指定的最小值。

StringBuilder 的操作

StringBuilder 提供的主要操作在 String 中不可用,即 append() 和 insert() 方法,这些方法经过重载可接受任意类型的数据。它们会将参数转换为字符串,然后将该字符串的字符追加或插入到字符串构建器中的字符序列中。其中 append 方法始终将字符添加到现有字符序列的末尾,而 insert 方法则将字符添加到指定位置。

以下是 StringBuilder 类中的一些方法。

  • 您可以使用 append() 方法将任何基本类型或对象附加到字符串构建器上。在执行追加操作之前,数据会被转换为字符串。
  • delete(int start, int end) 方法从 StringBuilder 的字符序列中删除从 start 到 end - 1(包含 end)的子序列。
  • 你可以使用 deleteCharAt(int index) 方法删除索引为 index 的字符。
  • 您可以使用insert(int offset)方法在指定偏移量处插入任意基本类型或对象。这些方法将待插入的元素作为第二个参数接收。在执行插入操作前,数据会被转换为字符串。
  • 您可以使用replace(int start, int end, String s)和setCharAt(int index, char c)方法替换字符。
  • 你可以使用reverse()方法来反转此String Builder中字符的顺序。
  • 你可以使用 toString() 方法返回一个包含构建器中字符序列的字符串。

注意:您可以在 StringBuilder 对象上使用任何字符串方法,方法是先通过 StringBuilder 类的 toString() 方法将字符串构建器转换为字符串,然后使用 StringBuilder(String string) 构造函数将字符串重新转换为字符串构建器。

StringBuilder实战

在”字符串”章节中列出的 StringDemo 程序,就是一个若使用StringBuilder替代String将更高效的程序示例。
StringDemo 实现了回文字符串的反转功能。以下是该程序的代码列表:

public class PalindromeDemo {
    public static void main(String[] args) {
        String palindrome = "Dot saw I was Tod";
        int len = palindrome.length();
        char[] tempCharArray = new char[len];
        char[] charArray = new char[len];

        // put original string in an 
        // array of chars
        for (int i = 0; i < len; i++) {
            tempCharArray[i] = palindrome.charAt(i);
        }

        // reverse array of chars
        for (int j = 0; j < len; j++) {
            charArray[j] = 
              tempCharArray[len - 1 - j];
        }

        String reversePalindrome = new String(charArray);
        IO.println(reversePalindrome);
    }
}

程序运行结果如下

doT saw I was toD

为实现字符串反转,程序将字符串转换为字符数组(第一个for循环),将数组反转为第二个数组(第二个for循环),最后再转换回字符串。
若将回文字符串转换为字符串构建器,可使用StringBuilder类的reverse()方法。这能使代码更简洁易读:

public class StringBuilderDemo {
    public static void main(String[] args) {
       String palindrome = "Dot saw I was Tod";

       StringBuilder sb = new StringBuilder(palindrome);
       sb.reverse(); //reverse it
       IO.println(sb.toString());
    }
}

会有同样的输出:

doT saw I was toD

请注意,println() 会打印String Builder,例如:

IO.println(sb);

因为 sb.toString() 会被隐式调用,就像 println 调用中任何其他对象的情况一样。

注意:还存在一个StringBuffer类,其功能与StringBuilder类完全相同,区别在于StringBuffer通过同步方法实现了线程安全。除非您绝对需要线程安全的类,否则无需使用StringBuffer。