【问题标题】:String valueOf vs concatenation with empty string字符串 valueOf 与空字符串的连接
【发布时间】:2011-12-06 19:56:18
【问题描述】:

我从事 Java 代码优化工作。我不清楚String.valueOf+"" 标志之间的区别:

int intVar = 1;
String strVar = intVar + "";
String strVar = String.valueOf(intVar);

第 2 行和第 3 行有什么区别?

【问题讨论】:

标签: java


【解决方案1】:
public void foo(){
int intVar = 5;
String strVar = intVar+"";    
}

这种方法使用 StringBuilder 来创建结果字符串

public void foo();
  Code:
   0:   iconst_5
   1:   istore_1
   2:   new     #2; //class java/lang/StringBuilder
   5:   dup
   6:   invokespecial   #3; //Method java/lang/StringBuilder."<init>":()V
   9:   iload_1
   10:  invokevirtual   #4; //Method java/lang/StringBuilder.append:(I)Ljava/lan
g/StringBuilder;
   13:  ldc     #5; //String
   15:  invokevirtual   #6; //Method java/lang/StringBuilder.append:(Ljava/lang/
String;)Ljava/lang/StringBuilder;
   18:  invokevirtual   #7; //Method java/lang/StringBuilder.toString:()Ljava/la
ng/String;
   21:  astore_2
   22:  return

public void bar(){
int intVar = 5;
String strVar = String.valueOf(intVar);
}

此方法仅调用 String 的静态方法来获取 int 的 String 版本

public void bar();
  Code:
   0:   iconst_5
   1:   istore_1
   2:   iload_1
   3:   invokestatic    #8; //Method java/lang/String.valueOf:(I)Ljava/lang/Stri
ng;
   6:   astore_2
   7:   return

依次调用Integer.toString()

【讨论】:

  • 这并没有告诉我们 JIT 编译器是否会(特别是)将第一个版本优化为更简单的形式。
  • 那么哪个更好?
【解决方案2】:

问问自己代码的用途。是不是:

  • 将空字符串与值连接
  • 将值转换为字符串

对我来说,这听起来更像是后者……这就是我使用String.valueOf 的原因。每当您可以让您的代码以与描述您想要实现的目标相同的方式阅读时,这都是一件好事。

请注意,这适用于所有类型,并且在传递空引用而不是抛出 NullPointerException 时将返回“null”。如果您正在使用一个类(而不是本示例中的 int)并且您希望它在它为 null 时引发异常(例如,因为它代表一个错误),请调用 toString on而是参考。

【讨论】:

  • String.valueOf(int x) 简单地调用 String 的静态方法来获取 int 的 String 版本。当我们谈论Android时,建议避免使用静态方法。您如何看待 Android 中的这种方法?
【解决方案3】:

使用String.valueOf(int),或者更好,Integer.toString(int) 对机器来说相对更有效。但是,除非性能至关重要(在这种情况下,我不建议您使用任何一种)然后""+ x 可以更有效地利用您的时间。恕我直言,这通常更重要。有时更重要。

换句话说,""+ 浪费了一个对象,但Integer.toString() 无论如何都会创建多个对象。要么您的时间更重要,要么您想不惜一切代价避免创建对象。您不太可能认为创建多个对象是可以的,但再创建一个则不行。

【讨论】:

  • 不错的短语:“那么”“+ x 可以更有效地利用您的时间。恕我直言,这通常更重要。”
【解决方案4】:

我更喜欢valueOf(),因为我认为它更具可读性和明确性。

对性能的任何担忧都是无法衡量的微优化。在我进行测量并看到它们有所作为之前,我不会担心它们。

【讨论】:

    【解决方案5】:

    第一行等价于

    String strVal = String.valueOf(intVar) + "";
    

    所以有一些额外的(和毫无意义的)工作要做。不确定编译器是否优化了空字符串文字的连接。如果没有(并且查看@Jigar 的答案显然没有),这将反过来成为

    String strVal = new StringBuilder().append(String.valueOf(intVar))
                          .append("").toString();
    

    所以你真的应该直接使用 String.valueOf 。

    【讨论】:

      【解决方案6】:

      好吧,如果你查看 JRE 源代码,Integer.getChars(...) 是最重要的方法,它实际上将整数转换为 char[],但它是包私有方法。
      所以问题是如何以最小的开销调用这个方法。
      以下是通过跟踪对目标方法的调用来概述这 3 种方法,请查看 JRE 源代码以更好地理解这一点。

      1. "" + intVar 编译为:
        new StringBuilder() => StringBuilder.append(int) => Integer.getChars(...)
      2. String.valueOf(intVar) => Integer.toString(intVar) => Integer.getChars(...)
      3. Integer.toString(intVar) => Integer.getChars(...)

      第一种方法不必要地创建了一个额外的对象,即 StringBuilder。
      第二个简单地委托给第三种方法。
      所以你现在有了答案。

      PS:各种编译时间和运行时优化在这里发挥作用。因此,实际的性能基准可能会根据我们无法预测的不同 JVM 实现说明其他内容,因此我通常更喜欢通过查看源代码看起来高效的方法。

      【讨论】:

        【解决方案7】:

        从优化的角度来看,我总是更喜欢两者之间的String.valueOf()。第一个只是一个hack,试图欺骗将intVar转换为String,因为+运算符。

        【讨论】:

          【解决方案8】:

          尽管这里的答案总体上是正确的,但有一点没有提到。

          "" + intVarString.valueOf()Integer.toString() 相比具有更好的性能。因此,如果性能很关键,最好使用空字符串连接。

          参见 Aleksey Shipilëv 的 this talk。或these slides 同一个演讲(幻灯片#24)

          【讨论】:

          • 真的很有趣!很高兴知道。感谢您的建议。
          【解决方案9】:

          连接字符串和其他变量实际上在下面使用String.valueOf()(和StringBuilder),因此编译器有望丢弃空字符串并在两种情况下生成相同的字节码。

          【讨论】:

          • 看@Jigar 的回答显然没有做这个优化
          • @Thilo:不过 Java 编译器不止一个。
          【解决方案10】:
          String strVar1 = intVar+"";
          String strVar2 = String.valueOf(intVar);
          

          strVar1 等价于 strVar2,但使用 int+emptyString "" 这不是优雅的方式。

          使用 valueOf 更有效。

          【讨论】:

            猜你喜欢
            • 2015-01-13
            • 1970-01-01
            • 2010-09-29
            • 2016-07-19
            • 1970-01-01
            • 2011-06-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多