Java 添加一个空字符串vs toString-为什么它不好?

Java 添加一个空字符串vs toString-为什么它不好?,java,string,tostring,pmd,Java,String,Tostring,Pmd,根据PMD工具,以下为不良做法: String s = "" + 123; // bad String t = Integer.toString(456); // ok This is an inefficient way to convert any type to a `String`. 为什么这样做是一件坏事?它扩展到“+String.valueOf(yourObject)”,因此进行了不必要的连接。连接包括分配一个额外的字符串并对字符串的值进行额外的复制。这是低效的,因为它涉及

根据PMD工具,以下为不良做法:

String s = "" + 123; // bad 
String t = Integer.toString(456); // ok 


This is an inefficient way to convert any type to a `String`.

为什么这样做是一件坏事?

它扩展到“+String.valueOf(yourObject)”,因此进行了不必要的连接。连接包括分配一个额外的字符串并对字符串的值进行额外的复制。

这是低效的,因为它涉及一个不必要的字符串连接,因此创建一个或两个额外的
string
对象-尽管我相信JIT可以优化它

对我来说,更大的问题是代码不够清晰。调用
toString
是一种标准的习惯用法,每个Java开发人员都能理解(希望:-),所以您应该更喜欢这样

String s = "" + 123; // bad     
String t = Integer.toString(456);
将汇编为:

String s = "123";
String t = Integer.toString(456);
所以:“+123显然稍微好一点已检查

publicstaticvoidmain(字符串参数[])
{
//0:ldc1#16
//12:astore_1
//23:sipush 456
//36:invokestatic#18
//4.9:astore_2
//5 10:getstatic#24
//6 13:新#30
//7 16:dup
//8 17:aload_1
//9 18:invokestatic#32
//10 21:38
//11 24:aload_2
//12 25:invokevirtual#41
//13 28:invokevirtual#45
//14 31:invokevirtual#48
//15 34:返回
}
编辑:

对于非常量值:

int i = 123;
String s = (new StringBuilder()).append(i).toString();
String t = Integer.toString(i);
System.out.println((new StringBuilder(String.valueOf(s))).append(t).toString());

    public static void main(String args[])
    {
    //    0    0:bipush          123
    //    1    2:istore_1
    //    2    3:new             #16  <Class StringBuilder>
    //    3    6:dup
    //    4    7:invokespecial   #18  <Method void StringBuilder()>
    //    5   10:iload_1
    //    6   11:invokevirtual   #19  <Method StringBuilder StringBuilder.append(int)>
    //    7   14:invokevirtual   #23  <Method String StringBuilder.toString()>
    //    8   17:astore_2
    //    9   18:iload_1
    //   10   19:invokestatic    #27  <Method String Integer.toString(int)>
    //   11   22:astore_3
    //   12   23:getstatic       #32  <Field PrintStream System.out>
    //   13   26:new             #16  <Class StringBuilder>
    //   14   29:dup
    //   15   30:aload_2
    //   16   31:invokestatic    #38  <Method String String.valueOf(Object)>
    //   17   34:invokespecial   #44  <Method void StringBuilder(String)>
    //   18   37:aload_3
    //   19   38:invokevirtual   #47  <Method StringBuilder StringBuilder.append(String)>
    //   20   41:invokevirtual   #23  <Method String StringBuilder.toString()>
    //   21   44:invokevirtual   #50  <Method void PrintStream.println(String)>
    //   22   47:return
    }
inti=123;
字符串s=(新的StringBuilder()).append(i).toString();
字符串t=整数。toString(i);
System.out.println((新的StringBuilder(String.valueOf)).append(t.toString());
公共静态void main(字符串参数[])
{
//0:bipush 123
//1.2:istore_1
//2 3:新#16
//36:dup
//4.7:特别是
//5 10:iload_1
//6 11:invokevirtual#19
//7 14:invokevirtual#23
//8 17:astore_2
//9 18:iload_1
//10 19:invokestatic#27
//11 22:astore_3
//12 23:getstatic#32
//13 26:新#16
//14:29:dup
//15 30:aload_2
//16 31:invokestatic#38
//17 34:特别是
//18 37:aload_3
//19 38:invokevirtual#47
//20 41:invokevirtual#23
//21 44:invokevirtual#50
//22 47:返回
}

上面的代码创建了一个临时字符串,将“”和123组合在一起,而tostring版本清楚地说明了这一意图。“将此值转换为字符串”从代码生成的角度来看,这并不是严格正确的,因此我将避免使用向上投票。它实际上(对于我测试过的Java 6u20)扩展为:
new StringBuilder().append(“”).append(yourObject).toString()
,假设
yourObject
不是常量。我不确定我是否在跟踪你。你证明了“+123”比Integer.toString(123)好吗?实际检查是+1。那么,对象类型而不是pod类型呢?“+123是一个常量表达式,编译器已经将其评估为“123”。@stacker:“因此:“+123明显稍微好一些”更好是主观的,唯一明显的是它更快。为了性能而牺牲可读性,没有已知的性能问题,过早的优化通常被认为是错误的。我认为,将此标记为答案是误导和无益的。正如Chris Jester Young指出的,只有在int为final的情况下,它才会更快。为了生成更好的代码,在int为final的情况下,应该将该int对应的字符串表示为也是final的字符串(这是编译器自动执行的操作)
“+123
一点也不“更好”,它相当于用值声明一个新的静态字符串
“123”
,与int
123
无关。显然,对于常量(静态/最终)”“+123更有效。对于其他值,使用toString更有效。“Static/final”可能会产生误导。字段必须是静态的和最终的,才能被视为常量,并且仅适用于原语和字符串。(局部变量从不被认为是常数。)可能的重复不是那么简单。见斯塔克的答案。如果不是123,而是一个非常量值,那么你是正确的。代码透明性对我来说是至关重要的。代码清晰性应该始终先于微观优化。
int i = 123;
String s = (new StringBuilder()).append(i).toString();
String t = Integer.toString(i);
System.out.println((new StringBuilder(String.valueOf(s))).append(t).toString());

    public static void main(String args[])
    {
    //    0    0:bipush          123
    //    1    2:istore_1
    //    2    3:new             #16  <Class StringBuilder>
    //    3    6:dup
    //    4    7:invokespecial   #18  <Method void StringBuilder()>
    //    5   10:iload_1
    //    6   11:invokevirtual   #19  <Method StringBuilder StringBuilder.append(int)>
    //    7   14:invokevirtual   #23  <Method String StringBuilder.toString()>
    //    8   17:astore_2
    //    9   18:iload_1
    //   10   19:invokestatic    #27  <Method String Integer.toString(int)>
    //   11   22:astore_3
    //   12   23:getstatic       #32  <Field PrintStream System.out>
    //   13   26:new             #16  <Class StringBuilder>
    //   14   29:dup
    //   15   30:aload_2
    //   16   31:invokestatic    #38  <Method String String.valueOf(Object)>
    //   17   34:invokespecial   #44  <Method void StringBuilder(String)>
    //   18   37:aload_3
    //   19   38:invokevirtual   #47  <Method StringBuilder StringBuilder.append(String)>
    //   20   41:invokevirtual   #23  <Method String StringBuilder.toString()>
    //   21   44:invokevirtual   #50  <Method void PrintStream.println(String)>
    //   22   47:return
    }
String s = "" + 123; // bad