我们必须一直为日志输出构建字符串等等。在JDK版本中,我们已经学习了什么时候使用StringBuffer(许多追加,线程安全)和StringBuilder(许多追加,非线程安全)。

使用String.format()有什么建议?它是有效的,还是我们被迫坚持在性能很重要的一行程序中使用连接?

例如,丑陋的老式风格,

String s = "What do you get if you multiply " + varSix + " by " + varNine + "?";

vs.整洁的新样式(字符串。格式,可能更慢),

String s = String.format("What do you get if you multiply %d by %d?", varSix, varNine);

注意:我的特定用例是代码中的数百个“一行”日志字符串。它们不涉及循环,所以StringBuilder太重量级了。我对String.format()特别感兴趣。


当前回答

在您的示例中,性能可能没有太大不同,但还有其他问题需要考虑:即内存碎片。连接操作也在创建一个新字符串,即使它是临时的(GC需要时间,而且工作量更大)。String.format()可读性更强,涉及的碎片更少。

此外,如果你经常使用特定的格式,不要忘记你可以直接使用Formatter()类(所有String.format()所做的是实例化一个使用Formatter实例)。

此外,还应该注意其他一些事情:小心使用substring()。例如:

String getSmallString() {
  String largeString = // load from file; say 2M in size
  return largeString.substring(100, 300);
}

这个大字符串仍然在内存中,因为这就是Java子字符串的工作方式。一个更好的版本是:

  return new String(largeString.substring(100, 300));

or

  return String.format("%s", largeString.substring(100, 300));

如果你同时做其他事情,第二种形式可能更有用。

其他回答

你的旧样式会被JAVAC 1.6自动编译为:

StringBuilder sb = new StringBuilder("What do you get if you multiply ");
sb.append(varSix);
sb.append(" by ");
sb.append(varNine);
sb.append("?");
String s =  sb.toString();

所以这和使用StringBuilder是没有区别的。

字符串。format要重量级得多,因为它创建了一个新的Formatter,解析输入格式字符串,创建一个StringBuilder,将所有内容附加到它并调用toString()。

通常应该使用String。格式,因为它相对较快,并且支持全球化(假设您实际上正在尝试编写用户可以阅读的内容)。如果您试图翻译一个字符串,而不是每个语句翻译3个或更多字符串(特别是对于语法结构截然不同的语言),它还可以使全球化变得更容易。

现在,如果您不打算翻译任何东西,那么要么依赖于Java内置的+运算符到StringBuilder的转换。或者显式地使用Java的StringBuilder。

Java的字符串。格式如下:

它解析格式字符串,分解成一个格式块列表 它迭代格式块,呈现为一个StringBuilder,这基本上是一个数组,根据需要调整自己的大小,通过复制到一个新的数组。这是必要的,因为我们还不知道分配最终字符串的大小 StringBuilder.toString()将他的内部缓冲区复制到一个新的String中

如果这个数据的最终目的地是一个流(例如,渲染一个网页或写入一个文件),你可以将格式块直接组装到你的流中:

new PrintStream(outputStream, autoFlush, encoding).format("hello {0}", "world");

我推测优化器将优化掉格式字符串处理。如果是这样,就剩下了与手动展开String相同的平摊性能。格式转换为StringBuilder。

这个问题的答案在很大程度上取决于您特定的Java编译器如何优化它生成的字节码。字符串是不可变的,理论上,每个“+”操作都可以创建一个新的字符串。但是,你的编译器几乎肯定会优化掉构建长字符串的中间步骤。上面的两行代码完全有可能生成完全相同的字节码。

唯一真正了解的方法是在当前环境中迭代地测试代码。编写一个QD应用程序,以迭代的方式连接字符串,并查看它们如何彼此超时。

在您的示例中,性能可能没有太大不同,但还有其他问题需要考虑:即内存碎片。连接操作也在创建一个新字符串,即使它是临时的(GC需要时间,而且工作量更大)。String.format()可读性更强,涉及的碎片更少。

此外,如果你经常使用特定的格式,不要忘记你可以直接使用Formatter()类(所有String.format()所做的是实例化一个使用Formatter实例)。

此外,还应该注意其他一些事情:小心使用substring()。例如:

String getSmallString() {
  String largeString = // load from file; say 2M in size
  return largeString.substring(100, 300);
}

这个大字符串仍然在内存中,因为这就是Java子字符串的工作方式。一个更好的版本是:

  return new String(largeString.substring(100, 300));

or

  return String.format("%s", largeString.substring(100, 300));

如果你同时做其他事情,第二种形式可能更有用。