String Valueof VS Concatenation with Empty String

String valueOf vs concatenation with empty string

public void foo(){
int intVar = 5;
String strVar = intVar+"";
}

This approach uses StringBuilder to create resultant String

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);
}

This approach invokes simply a static method of String to get the String version of int

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

which in turn calls Integer.toString()

String.valueOf(someVar) vs ( + someVar)

When you do "" that is not going to create an Object. It is going to create a String literal. There is a differenc(How can a string be initialized using " "?) actually.

Coming to your actual question,

From String concatenation docs

The Java language provides special support for the string concatenation operator ( + ), and for conversion of other objects to strings. String concatenation is implemented through the StringBuilder(or StringBuffer) class and its append method.

So unnecissarly you are creating StringBuilder object and then that is giving another String object.

However valueOf directly give you a String object. Just go for it.

Besides the performance, just think generally. Why you concatenating with empty string, when actually you want to convert the int to String :)

Why is String concatenation faster than String.valueOf for converting an Integer to a String?

As you've mentioned, HotSpot JVM has -XX:+OptimizeStringConcat optimization that recognizes StringBuilder pattern and replaces it with highly tuned hand-written IR graph, while String.valueOf() relies on general compiler optimizations.

I've found the following key differences by analyzing the generated assembly code:

  • Optimized concat does not zero char[] array created for the result string, while the array created by Integer.toString is cleared after allocation just like any other regular object.
  • Optimized concat translates digits to chars by simple addition of '0' constant, while Integer.getChars uses table lookup with the related array bounds check etc.

There are other minor differences in the implementation of PhaseStringOpts::int_getChars vs. Integer.getChars, but I guess they are not that significant for performance.


BTW, if you take a bigger number (e.g. 1234567890), the performance difference will be negligible because of an extra loop in Integer.getChars that converts two digits at once.

String Concatenation - valueOf or not

When we concatenate strings, the compiler actually translates it to StringBuffer.append().

The underlying implementations for StringBuffer.append(int) and String.valueOf(int) both eventually end up calling Integer.getChars(int,int,char[]) except that in case of String.valueOf(), there is a call to Integer.toString(int) first.

To conclude, for the given scenario, directly concatenating would be the way to go. But if you intend to be conscious about memory, then use string-builder to concatenate values first and then log it.

Why concatenate strings with an empty value before returning the value?

One is a String, the other is char. It's useful to always be dealing with a String, rather than having to check if it's a char.

java type-conversion String.valueOf( ) vs variable +

In Java the strings have the special operator + which is concatenation. If the operands of the concatenation are not strings their respective .toString method is called, and if it is the value is null the "null" string is concatenated. Most modern JITs or even compilers might decide to use a stringbuilder. So the only danger here is that you create extra objects which get discarded. Additionally, this code might be less readible or more confusing.

Is concatenating with an empty string to do a string conversion really that bad?

Your arguments are good; this is one of the more expressive areas of the Java language, and the "" + idiom seems well entrenched, as you discovered.

See String concatenation in the JLS. An expression like

"" + c1 + c2

is equivalent to

new StringBuffer().append(new Character(c1).toString())
.append(new Character(c2).toString()).toString()

except that all of the intermediate objects are not necessary (so efficiency is not a motive). The spec says that an implementation can use the StringBuffer or not. Since this feature is built into the language, I see no reason to use the more verbose form, especially in an already verbose language.

Add an empty string vs toString - why is it bad?

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

Will be compiled to:

String s = "123";
String t = Integer.toString(456);

so: "" +123 is obvious slightly better! Checked with JAD

public static void main(String args[])
{
// 0 0:ldc1 #16 <String "123">
// 1 2:astore_1
// 2 3:sipush 456
// 3 6:invokestatic #18 <Method String Integer.toString(int)>
// 4 9:astore_2
// 5 10:getstatic #24 <Field PrintStream System.out>
// 6 13:new #30 <Class StringBuilder>
// 7 16:dup
// 8 17:aload_1
// 9 18:invokestatic #32 <Method String String.valueOf(Object)>
// 10 21:invokespecial #38 <Method void StringBuilder(String)>
// 11 24:aload_2
// 12 25:invokevirtual #41 <Method StringBuilder StringBuilder.append(String)>
// 13 28:invokevirtual #45 <Method String StringBuilder.toString()>
// 14 31:invokevirtual #48 <Method void PrintStream.println(String)>
// 15 34:return
}

EDIT:

For non-constant values:

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
}

How can an empty string plus an object equal a number

You are creating an object, v, and overriding its valueOf() method to return the integer 5. If an object does not have an explicit valueOf() method defined, then valueOf() returns the object itself. All built-in core objects in JavaScript override this method to return the appropriate value. For example, doing the following:

x = 5;
console.log(x)

is really doing:

console.log(x.valueOf()) // log the return value of x.valueOf()

You can read more about valueOf() here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/valueOf


If you are asking about why the addition (+) operator returns an arithmetic addition (calling v.valueOf()) instead of concatenation, you need to refer to the ECAMScript specification for the answer. Section 11.6.1 talks about the addition operator. Here is the relevant bit:


  1. Let lprim be ToPrimitive(lval).
  2. Let rprim be ToPrimitive(rval).
  3. If Type(lprim) is String or Type(rprim) is String, then Return the String that is the result of concatenating ToString(lprim) followed by ToString(rprim)
  4. Return the result of applying the addition operation to ToNumber(lprim) and ToNumber(rprim).

It looks like the operands should be resolved into string types before number types, so your expression ''+v should call v.toString() first, and thus return foo, right?

Actually, no. Because in step 5 and 6, both operands are resolved into their primitives first, and this resolution is done without "hint". When there is no hint passed to ToPrimitive, Objects return their default values, which is the return of the valueOf() method. See section 9.1 for how Objects resolve into their primitives.

difference between String.valueOf(int) , `+` string operator and Integer.toString(int)

For the example you have given, the answer will really depend on the type of 'integer' you are using.

loadCity(countryName , countryId + "");

For an Integer object this is equivelent to :

loadCity(countryName, countryId.toString() + "");

Whereas for an int primitive, this code is equivelent to :

loadCity(countryName, String.valueOf(countryId) + "");

In either case, as ArjunShankar pointed out there is a good chance that the compiler has optimised your code anyway. So if your question is 'do I go back and refactor all my code?', then I would say 'don't sweat the small stuff'. But in the future use a more conventional approach to avoid the down votes.



Related Topics



Leave a reply



Submit