如何有效地使用 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" 是什么。
过去,我一直使用 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" 是什么。