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 Strings,但 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】:

我对@9​​87654321@ 的主要担忧是它是特定于语言环境的操作,如果您的代码在不同的语言环境中运行,您最终可能会得到无法预料的结果。

我希望有一个非语言环境替代它,因为它的紧凑语法非常好。

【讨论】:

【参考方案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() 与字符串内的 作为字符串 [重复]

string.format 与 css 标签冲突: 的

几种常见的字符串连接方法连接速度分析

在 Xcode11 Beta 4 中将 String(format: , args) 与 SwiftUI 一起使用时出错

String.format与手机设置的语言环境的关系导致语言转换系统无法识别闪退问题