String.format() 与“+”运算符 [重复]
Posted
技术标签:
【中文标题】String.format() 与“+”运算符 [重复]【英文标题】:String.format() vs "+" operator [duplicate] 【发布时间】:2012-11-28 17:14:26 【问题描述】:基本的字符串连接操作应该使用什么?
String randomString = "hello " + userName + " how are you" ?
或
String randomString = String.format("hello %s how are you ?",userName);
我觉得String.format()
可以更好地了解输出字符串。
但是,使用其中任何一种方法实际上利弊是什么?
在字符串文字池中是否有任何性能或孤立条目。
编辑:我说的是字符串中的多个参数,而不仅仅是一个。大约 5 +。
额外问题:也请分享您对 哪个应该实际使用?这些或第三个中的任何一个......! ?
【问题讨论】:
可能与***.com/q/925423/1135954重复 @mtk 这个问题的答案中一个有趣的地方是本地化的想法。使用字符串国际化,您可以将第一个参数切换到String.format
,使用具有不同参数顺序或措辞的参数,而无需重新编译。这是String.format
的巨大力量。
【参考方案1】:
基本的字符串连接操作应该使用什么?
您提供的示例有不同的用途。 +
重载为 concat String
s,但 String.format
用于格式化字符串,正如名称所指定的那样。
将字符串连接在一起并不是主要工作。
所以,如果要求只是连接使用+
或concat 方法。
这些链接会很有用:
Should I use Java's String.format() if performance is important?
Is it better practice to use String.format over string Concatenation in Java?
【讨论】:
但我经常看到 String.format() 用于连接目的而不是实际“格式化”字符串。 你不应该。但如果还需要格式化,首选format
。【参考方案2】:
如果您只追求性能,我相信使用StringBuilder/StringBuffer
是构建字符串的最有效方式。即使 Java 编译器足够聪明,可以将大部分字符串连接转换为 StringBuilder
等效项。
如果您正在寻找可读性,我认为String.format
会更清晰,除非我需要依赖高性能,否则我也会使用它。
因此,如果您的主要关注点不是性能,这意味着此代码不在经常调用的路径中,您可能更喜欢使用String.format
,因为它可以更好地了解结果字符串(如您所说)。
此外,使用String.format
可以让您使用格式的东西,这意味着您可以使用它来填充字符串、格式化数字、日期等,如果使用简单的连接会使代码变得更糟。
编辑 为 Chuu:
使用JAD,可以看到如下代码:
public class Test
public static void main(String[] args)
String str = "a" + "b" + "c";
String str2 = "foo" + str + "bar" + str;
System.out.println(str2);
反编译后的样子:
public class Test
public static void main(String[] args)
String str = "abc";
String str2 = new StringBuilder("foo").append(str).append("bar").append(str).toString();
System.out.println(str2);
也可以使用javap
实用程序找到证明,该实用程序将在.class
文件下显示Java 字节码:
public static void main(java.lang.String[] args);
0 ldc <String "abc"> [16]
2 astore_1 [str]
3 new java.lang.StringBuilder [18]
6 dup
7 ldc <String "foo"> [20]
9 invokespecial java.lang.StringBuilder(java.lang.String) [22]
12 aload_1 [str]
13 invokevirtual java.lang.StringBuilder.append(java.lang.String) : java.lang.StringBuilder [25]
16 ldc <String "bar"> [29]
18 invokevirtual java.lang.StringBuilder.append(java.lang.String) : java.lang.StringBuilder [25]
21 aload_1 [str]
22 invokevirtual java.lang.StringBuilder.append(java.lang.String) : java.lang.StringBuilder [25]
25 invokevirtual java.lang.StringBuilder.toString() : java.lang.String [31]
28 astore_2 [str2]
29 getstatic java.lang.System.out : java.io.PrintStream [35]
32 aload_2 [str2]
33 invokevirtual java.io.PrintStream.println(java.lang.String) : void [41]
36 return
【讨论】:
我不知道 android 的 java 实现的具体细节,但在大多数动态语言中,'+' 运算符始终是连接字符串的最快方法。这是因为大多数抖动会将其转换为计算结果字符串的大小,进行一次内存分配,然后将所有内容复制到它分配的内存中。 String.format 和 StringBuffer 都需要多次动态分配和/或创建要收集的临时对象。 Java 编译器会自动将"a" + "b" + "c"
转换为"abc"
,但如果涉及变量,它会尽可能使用StringBuilder
,因此String str1 = "a"; String str2 = "a" + str1;
将被转换为String str2 = new StringBuilder("a").append(str1)).toString();
。可以使用 JAD 等 Java 反编译器验证此行为。
@Chuu 另见上面的编辑。
@Alex:Chuu 的说法似乎是关于 JIT:ers 的。它们在运行时和加载时进行优化,这在类文件中不可见。
@Alex 你的意思是String str = "abc";
而不是反编译文件中的String str = "ac";
?【参考方案3】:
我对@987654321@ 的主要担忧是它是特定于语言环境的操作,如果您的代码在不同的语言环境中运行,您最终可能会得到无法预料的结果。
我希望有一个非语言环境替代它,因为它的紧凑语法非常好。
【讨论】:
【参考方案4】:在我看来,使用+ operator
。
如果性能是一个问题,您应该使用StringBuilder
,正如 Alex 在上面的评论中指出的那样,Java 编译器将转换:
String str2 = "a" + str1;
收件人:String str2 = new StringBuilder("a").append(str1)).toString();
除此之外,您还可以使用+ operator
避免运行时异常。相反,您会得到可以在编译时捕获的语法错误。例如:
String var = "huge success.";
System.out.print( "I'm making a note here: " + var );
//System.out.print( "Printing: " + ); Syntax error!
System.out.print( String.format( "I'm making a note here: '%s'", var ) );
System.out.print( String.format( "I'm making a note here: '%s'" ) ); // runtime exception!
System.out.print( String.format( "I'm making a note here: '%d'", var ) ); // runtime exception!
可读性取决于个人喜好。但是我会说String.format
语法基本上来自 C++,并且从那时起创建的大多数语言出于可读性原因都采用了+ operator
。
【讨论】:
【参考方案5】:我的两分钱:总是用String.format()
在这种情况下,国际化比风格或性能更受关注。出于这个原因,我总是使用String.format()
英文文本:"Hello " + userName + " how are you?"
翻译成绝地:userName + "you are how? Hello!"
如果字符串被连接起来,改变词序对于翻译者来说即使不是不可能也很困难。随着字符串的片段和占位符越来越多,这个问题变得越来越严重。
【讨论】:
【参考方案6】:我认为String.Format更高效,因为它有以下优点,
-
提高了可读性
更好的可翻译性
您可以在格式字符串中使用格式提供程序和简单的格式指示符(如固定宽度)。
您可以通过将格式字符串放入配置文件中来做一些强大的事情。
String.Format() 通常更快,因为它在后台使用 StringBuilder 和高效的状态机,而 .Net 中的字符串连接相对较慢。随着字符串大小和替换值数量的增加,尤其如此。
谢谢。
【讨论】:
【参考方案7】:试试这个
long t0 = System.currentTimeMillis();
String userName = "test";
for (int i = 0; i < 1000000; i++)
String randomString = "hello " + userName + " how are you?";
// String randomString = String.format("hello %s how are you ?",userName);
System.out.println(System.currentTimeMillis() - t0);
您会惊讶地发现连接比 String.format 快 10 倍。但是 format 可以对数字、日期等做很多非常有用的事情。有关详细信息,请参阅 String.format 实际使用的 java.util.Formatter API。
【讨论】:
+1 用于性能测试 由于编译器是使用 + 运算符连接到 StringBuilder 实现,它会更快。但是,是的! String.format 就连接而言要慢得多。【参考方案8】:大多数推荐使用 StringBuffer 的人都生活在过去。 当前的最佳实践是使用 StringBuilder。但这可能会改变,那么为什么不让编译器为你做呢? 当你只使用“+”时,编译器会选择当前最好的实现,它甚至可以组合静态字符串(“foo”+“bar”将成为单个“foobar”)。
我会显式分配 StringBuilder 的唯一位置是在 Loops 中(它在循环之前创建并在其中使用)。
如果您不确定会发生什么,请检查生成的字节码。
那么什么时候使用格式呢?当实际的 formatting 很复杂时,我会使用 format。但是您现在正在谈论简单的串联。
【讨论】:
【参考方案9】:我个人更喜欢使用格式化,因为它看起来更好,而且我无法想象它会严重影响性能。
【讨论】:
以上是关于String.format() 与“+”运算符 [重复]的主要内容,如果未能解决你的问题,请参考以下文章
将 Spannable 与 String.format() 结合使用
string.format() 与字符串内的 作为字符串 [重复]
在 Xcode11 Beta 4 中将 String(format: , args) 与 SwiftUI 一起使用时出错