在 Java 中使用 String.format 比字符串连接更好吗?
在 Java 中使用 String.format 和字符串连接之间有明显的区别吗?
我倾向于使用 String.format
但偶尔会滑动并使用串联。 我想知道其中一个是否比另一个更好。
在我看来,String.format
为您提供了更多“格式化”字符串的功能; 连接意味着您不必担心意外添加额外的 %s 或漏掉一个。
String.format
也更短。
哪一种更具可读性取决于您的大脑如何工作。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(16)
我建议最好使用
String.format()
。 主要原因是String.format()
可以使用从资源文件加载的文本更轻松地本地化,而如果不为每种语言生成具有不同代码的新可执行文件,则无法本地化串联。如果您计划使您的应用程序可本地化,您还应该养成为格式标记指定参数位置的习惯:
然后可以对其进行本地化并交换名称和时间标记,而无需重新编译可执行文件以考虑到不同的排序。 通过参数位置,您还可以重复使用相同的参数,而无需将其传递到函数两次:
I'd suggest that it is better practice to use
String.format()
. The main reason is thatString.format()
can be more easily localised with text loaded from resource files whereas concatenation can't be localised without producing a new executable with different code for each language.If you plan on your app being localisable you should also get into the habit of specifying argument positions for your format tokens as well:
This can then be localised and have the name and time tokens swapped without requiring a recompile of the executable to account for the different ordering. With argument positions you can also re-use the same argument without passing it into the function twice:
关于性能:
计时结果如下:
因此,concatenation 比 String.format 快很多。
About performance:
The timing results are as follows:
Therefore, concatenation is much faster than String.format.
.format
的一个问题是失去静态类型安全性。 您的格式参数可能太少,并且格式说明符的类型可能错误 - 两者都会导致运行时IllegalFormatException
,因此您最终可能会得到记录破坏生产的代码。相反,
+
的参数可以由编译器测试。安全历史记录 post-tag" title="show questions tagged 'printf'" rel="tag">printf (
format
函数是在其上建模的)又长又可怕。One problem with
.format
is that you lose static type safety. You can have too few arguments for your format, and you can have the wrong types for the format specifiers - both leading to anIllegalFormatException
at runtime, so you might end up with logging code that breaks production.In contrast, the arguments to
+
can be tested by the compiler.The security history of printf (on which the
format
function is modeled) is long and frightening.由于有关于性能的讨论,我想我应该添加一个包括 StringBuilder 的比较。 事实上,它比 concat 和 String.format 选项更快。
为了进行同类比较,我在循环中而不是在外部实例化一个新的 StringBuilder (这实际上比仅进行一次实例化要快,很可能是由于在循环末尾重新分配空间的开销)一名建筑商)。
Since there is discussion about performance I figured I'd add in a comparison that included StringBuilder. It is in fact faster than the concat and, naturally the String.format option.
To make this a sort of apples to apples comparison I instantiate a new StringBuilder in the loop rather than outside (this is actually faster than doing just one instantiation most likely due to the overhead of re-allocating space for the looping append at the end of one builder).
你在那里得到了答案。
这是个人品味的问题。
我认为字符串连接速度稍快一些,但这应该可以忽略不计。
You got your answer right there.
It's a matter of personal taste.
String concatenation is marginally faster, I suppose, but that should be negligible.
这是一个以毫秒为单位的多个样本大小的测试。
}
Here's a test with multiple sample sizes in milliseconds.
}
这是与上面相同的测试,但修改为调用 StringBuilder 上的 toString() 方法。 下面的结果表明,StringBuilder 方法仅比使用 + 运算符的字符串连接慢一点。
文件:StringTest.java
Shell 命令:(编译并运行 StringTest 5 次)
结果:
Here's the same test as above with the modification of calling the toString() method on the StringBuilder. The results below show that the StringBuilder approach is just a bit slower than String concatenation using the + operator.
file: StringTest.java
Shell Commands : (compile and run StringTest 5 times)
Results :
String.format()
不仅仅是连接字符串。 例如,您可以使用String.format()
显示特定区域设置中的数字。但是,如果您不关心本地化,则没有功能差异。
也许连接比其他连接更快,但在大多数情况下,它可以忽略不计。
String.format()
is more than just concatenating strings. For example, you can display numbers in a specific locale usingString.format()
.However, if you don't care about localisation, there is no functional difference.
Maybe the concatenation is faster than the other but, in most cases, it will be negligible.
一般来说,字符串连接应该优先于
String.format
。 后者有两个主要缺点:对于第 1 点,我的意思是不可能理解
String.format()
调用在单个顺序传递中执行的操作。 人们被迫在格式字符串和参数之间来回切换,同时计算参数的位置。 对于短连接来说,这不是什么大问题。 然而,在这些情况下,字符串连接就不那么冗长了。第 2 点,我的意思是构建过程的重要部分是在格式字符串中编码的(使用 DSL)。 使用字符串来表示代码有很多缺点。 它本质上不是类型安全的,并且使语法突出显示、代码分析、优化等变得复杂。
当然,当使用 Java 语言外部的工具或框架时,新的因素可能会发挥作用。
Generally, string concatenation should be prefered over
String.format
. The latter has two main disadvantages:By point 1, I mean that it is not possible to understand what a
String.format()
call is doing in a single sequential pass. One is forced to go back and forth between the format string and the arguments, while counting the position of the arguments. For short concatenations, this is not much of an issue. In these cases however, string concatenation is less verbose.By point 2, I mean that the important part of the building process is encoded in the format string (using a DSL). Using strings to represent code has many disadvantages. It is not inherently type-safe, and complicates syntax-highlighting, code analysis, optimization, etc.
Of course, when using tools or frameworks external to the Java language, new factors can come into play.
错误的测试重复多次
您应该使用 {} no %s 。
}
Wrong test repeated many times
You should use {} no %s .
}
我没有做过任何具体的基准测试,但我认为串联可能会更快。 String.format() 创建一个新的 Formatter,后者又创建一个新的 StringBuilder(大小仅为 16 个字符)。 这是相当大的开销,特别是如果您正在格式化较长的字符串并且 StringBuilder 必须不断调整大小。
然而,串联的用处不大,而且更难阅读。 与往常一样,值得对您的代码进行基准测试,看看哪个更好。 将资源包、区域设置等加载到内存中并且对代码进行 JIT 编译后,服务器应用程序中的差异可能可以忽略不计。
也许作为最佳实践,最好使用适当大小的 StringBuilder(可附加)和区域设置创建自己的格式化程序,并在需要进行大量格式化时使用它。
I haven't done any specific benchmarks, but I would think that concatenation may be faster. String.format() creates a new Formatter which, in turn, creates a new StringBuilder (with a size of only 16 chars). That's a fair amount of overhead especially if you are formatting a longer string and StringBuilder keeps having to resize.
However, concatenation is less useful and harder to read. As always, it's worth doing a benchmark on your code to see which is better. The differences may be negligible in server app after your resource bundles, locales, etc are loaded in memory and the code is JITted.
Maybe as a best practice, it would be a good idea to create your own Formatter with a properly sized StringBuilder (Appendable) and Locale and use that if you have a lot of formatting to do.
可能存在明显的差异。
String.format
非常复杂,并且在底层使用正则表达式,因此不要养成在任何地方使用它的习惯,而只在需要的地方使用它。StringBuilder 会快一个数量级(正如这里有人已经指出的那样)。
There could be a perceptible difference.
String.format
is quite complex and uses a regular expression underneath, so don't make it a habit to use it everywhere, but only where you need it.StringBuilder
would be an order of magnitude faster (as someone here already pointed out).我认为我们可以使用
MessageFormat.format
因为它应该在可读性和性能方面都很好。我使用了 Icaro 在上面的答案中使用的相同程序,并通过附加使用
MessageFormat
解释性能数字的代码来增强它。更新:
根据 SonarLint 报告,应正确使用 Printf 样式格式字符串 (squid:S3457)
因为
方法。
printf 样式
格式字符串在运行时解释,而不是由编译器验证,它们可能包含导致创建错误字符串的错误。 当调用java.util.Formatter
、java 的 format(...) 方法时,此规则静态验证
、printf-style
格式字符串与其参数的相关性.lang.Stringjava.io.PrintStream
、MessageFormat
和java.io.PrintWriter
类以及java.io.PrintStream
或java.io.PrintWriter
类的 printf(...)我用大括号替换 printf 样式,得到了一些有趣的结果,如下所示。
我的结论:
正如我上面强调的,使用带有大括号的 String.format 应该是一个不错的选择,可以获得良好的可读性和性能。
I think we can go with
MessageFormat.format
as it should be good at both readability and also performance aspects.I used the same program which one used by Icaro in his above answer and I enhanced it with appending code for using
MessageFormat
to explain the performance numbers.UPDATES:
As per SonarLint Report, Printf-style format strings should be used correctly (squid:S3457)
Because
printf-style
format strings are interpreted at runtime, rather than validated by the compiler, they can contain errors that result in the wrong strings being created. This rule statically validates the correlation ofprintf-style
format strings to their arguments when calling the format(...) methods ofjava.util.Formatter
,java.lang.String
,java.io.PrintStream
,MessageFormat
, andjava.io.PrintWriter
classes and theprintf(...)
methods ofjava.io.PrintStream
orjava.io.PrintWriter
classes.I replace the printf-style with the curly-brackets and I got something interesting results as below.
My Conclusion:
As I highlighted above, using String.format with curly-brackets should be a good choice to get benefits of good readability and also performance.
习惯 String.Format 需要一些时间,但在大多数情况下这是值得的。 在 NRA 的世界中(从不重复任何内容),将标记化消息(日志或用户)保存在 Constant 库中(我更喜欢静态类)并根据需要使用 String.Format 调用它们,无论您是否是否本地化。 尝试将这样的库与串联方法一起使用时,使用任何需要串联的方法都更难以阅读、排除故障、校对和管理。 更换是一种选择,但我怀疑它的性能。 经过多年的使用,我对 String.Format 的最大问题是,当我将其传递给另一个函数(如 Msg)时,调用的长度太长,不方便,但是使用自定义函数作为别名很容易解决这个问题。
It takes a little time to get used to String.Format, but it's worth it in most cases. In the world of NRA (never repeat anything) it's extremely useful to keep your tokenized messages (logging or user) in a Constant library (I prefer what amounts to a static class) and call them as necessary with String.Format regardless of whether you are localizing or not. Trying to use such a library with a concatenation method is harder to read, troubleshoot, proofread, and manage with any any approach that requires concatenation. Replacement is an option, but I doubt it's performant. After years of use, my biggest problem with String.Format is the length of the call is inconveniently long when I'm passing it into another function (like Msg), but that's easy to get around with a custom function to serve as an alias.
格式 = 1508 毫秒
连接 = 31 毫秒
进程完成,退出代码为 0
连接比格式好得多。
Format = 1508 millisecond
Concatenation = 31 millisecond
Process finished with exit code 0
Concat is much better than format.
您无法通过上面的程序比较 String Concatenation 和 String.Format。
您也可以尝试在代码块中互换使用 String.Format 和 Concatenation 的位置,如下所示。
您会惊讶地发现 Format 在这里工作得更快。 这是因为创建的初始对象可能不会被释放,并且内存分配可能存在问题,从而影响性能。
You cannot compare String Concatenation and String.Format by the program above.
You may try this also be interchanging the position of using your String.Format and Concatenation in your code block like the below
You will be surprised to see that Format works faster here. This is since the intial objects created might not be released and there can be an issue with memory allocation and thereby the performance.