我想知道使用StringBuilder的这段代码是否最有效
还是通过将“”与当前项目连接在一起仍创建大量临时字符串?
如果可以的话,您可以建议使用更好的代码吗?
public String toString() {
StringBuilder out = new StringBuilder();
for (long item : someListOfNumbers) {
out.append( " " + item);
}
return out.toString();
}
答案 0 :(得分:4)
对于此特定用例,除非您的目标是在结果中留一个前导空格,否则您可能要使用StringJoiner
。
public String toString() {
StringJoiner joiner = new StringJoiner(" ");
someListOfNumbers.forEach(l -> joiner.add(Long.toString(l)));
return joiner.toString();
}
public String toString() {
returns someListOfNumbers.stream()
.map(String::valueOf)
.collect(Collectors.joining(" "));
}
StringBuilder
在构建文本时会更加高效,但是可以说上面的内容更具可读性。绝对可以避免在使用+
时使用StringBuilder
运算符,而应使用append()
之类的方法。
如果您查看this或this或其他答案,您会发现javac
编译器还进一步优化了字符串连接,例如如果常量用+
运算符连接,则编译器可以将结果常量插入字节码。
答案 1 :(得分:3)
out.append( " " + item);
在上面的语句中," " + item
似乎存在问题,因为它的组合字符串带有长号。由于字符串是不可变的,因此字符串的+
运算符会在内存中创建String的新副本。最佳解决方案可能是使用
out.append(' ').append(item);
甚至
out.append(" ").append(item);
在以上两种情况下,由于StringBuilder是Mutable的,因此不需要额外的内存空间来保存新的带修饰符的字符串。因此,它更理想。
答案 2 :(得分:1)
一种现代方法会将字符串生成器的操作留给库方法:
public String toString() {
return someListOfNumbers.stream()
.map(Number::toString)
.collect(Collectors.joining(" "));
}
我假设someListOfNumbers
是List<Long>
。我的方法给出的结果与您的结果不完全相同:您的结果有一个我遗漏的领先空间。如果需要该空间,可以自己添加或使用:
.collect(Collectors.joining(" ", " ", ""));
由三个参数joining
组成的分隔符,前缀和后缀按上述顺序(我将空字符串作为后缀)。
旁注:我曾经想使用.map(Long::toString)
,但由于其模棱两可而无法编译。这里的toString
可以指代无参数的Long.toString
或静态的一个参数Long.toString(long)
。我通过Long
:Number::toString
的超类解决了这个问题。另一个解决方案是.map(String::valueOf)
,如Karol Dowbecki的回答。
答案 3 :(得分:0)
为了摆脱尾随或前导零,您必须检查循环中当前处理的项目的索引。
以下是三个示例,它们构建了一个String
,此后没有任何内容可修剪:
public String toString() {
StringBuilder out = new StringBuilder();
// iterate in a classic for-loop checking for item at index 0
for (int i = 0; i < someListOfNumbers.size(); i++) {
long item = someListOfNumbers.get(i);
if (i == 0) {
// in this case, avoid a leading zero
out.append(item);
} else {
out.append(" ").append(item);
}
}
return out.toString();
}
public String toString() {
StringBuilder out = new StringBuilder();
// iterate in a classic for-loop checking for item at last index
for (int i = 0; i < someListOfNumbers.size(); i++) {
long item = someListOfNumbers.get(i);
if (i == someListOfNumbers.size() - 1) {
out.append(item).append(" ");
} else {
// this case avoids a trailing zero
out.append(item);
}
}
return out.toString();
}
public String toString() {
StringBuilder out = new StringBuilder();
// add the first element and iterate from 1 to end afterwards
// (this requires a check for an empty list)
out.append(someListOfNumbers.get(0));
for (int i = 1; i < someListOfNumbers.size(); i++) {
out.append(" ").append(someListOfNumbers.get(i));
}
return out.toString();
}
您甚至可以使用自己的方法,但是使用增强的for
循环,您将必须使用indexOf
然后执行检查。我不希望那样,但这是您的决定。