如何有效地使用 StringBuilder?

How can I efficiently use StringBuilder?

过去,我一直使用 printf 来格式化打印到控制台,但我目前的任务(创建发票报告)希望我们使用 StringBuilder,但我不知道如何不使用 StringBuilder对所需的每个间隙使用“”。例如...我应该打印出来

Invoice   Customer                                          Salesperson                      Subtotal        Fees       Taxes    Discount       Total
INV001    Company                                           Eccleston, Chris              $   2357.60 $     40.00 $    190.19 $  -282.91 $   2304.88

但我不知道如何使用 StringBuilder 使所有内容对齐。有什么建议吗?

StringBuilder 旨在减少与创建字符串相关的开销。

您可能知道也可能不知道,字符串是不可变的。这意味着

String a = "foo";
String b = "bar";
String c = a + b;
String d = c + c;

为每一行创建一个新字符串。如果我们只关心最后的字符串 d,那么带有字符串 c 的行就是在浪费 space,因为它在我们不需要的时候创建了一个新的 String 对象.

字符串生成器只是延迟实际生成 String 对象,直到您调用 .toString()。那时,它将内部 char[] 转换为实际字符串。

再举个例子

String foo() {
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < 100; i++)
       sb.append(i);
    return sb.toString();
}

在这里,我们只创建一个字符串。 StringBuilder 将在其内部 char[] value 中跟踪您添加到字符串中的字符。请注意,value.length 通常会大于您添加到 StringBuilder 中的字符总数,但如果字符串 value 可能 运行你正在建设变得太大。当发生这种情况时,它会调整大小,这意味着用更大的 char[] 替换 value,并将旧值以及您附加的任何字符复制到新数组。

最后,当您调用 sb.toString() 时,StringBuilder 将调用一个 String 构造函数,该构造函数接受一个 char[].

的参数

这意味着只创建了一个 String 对象,我们只需要足够的内存来存储我们的 char[] 并调整它的大小。

与以下比较:

String foo() {
    String toReturn = "";
    for (int i = 0; i < 100; i++)
       toReturn += "" + i;
    toReturn;
}

在这里,我们创建了 101 个字符串对象(也许更多,我不确定)。不过我们只需要一个!这意味着在每次调用时,我们都会处理 toReturn 表示的原始字符串,并创建另一个字符串。

特别是对于大字符串,这是非常昂贵的,因为在每次调用时,您都需要首先获取新字符串所需的内存,并释放旧字符串所拥有的内存。当事情保持简短时,这没什么大不了的,但是当你处理整个文件时,这很容易成为一个问题。

简而言之:如果您在完成输出之前添加/删除信息:使用 StringBuilder。如果您的字符串很短,为了方便起见,我认为正常连接就可以了,但这取决于您定义 "short" 是什么。