Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

String question

1 view
Skip to first unread message

stef

unread,
Jul 23, 2008, 5:59:17 AM7/23/08
to
Hello,

Silly question, but if - internally speaking- the java compiler
replace the "String" class with "StringBuffer",
what is the real purpose of "String" ? (except shorter keyword and,
may be, when who do static stuff like String s ="hello "+"world")

thanks...

Roedy Green

unread,
Jul 23, 2008, 6:41:27 AM7/23/08
to
On Wed, 23 Jul 2008 02:59:17 -0700 (PDT), stef
<stef.pe...@gmail.com> wrote, quoted or indirectly quoted someone
who said :

see http://mindprod.com/jgloss/immutable.html

for the advantages of immutable Strings.

Strings are immutable, StringBuilders are mutable.

String s = "hello" + "world";

is covertly converted by the compiler to:

String s = "helloworld";


at compile time, so there is no run time concatenation.

However

String s = hello + world;

is effectively the same as:

StringBuilder temp = new StringBuilder();
temp.append( hello );
temp.append( world );
s = temp.toString();
--

Roedy Green Canadian Mind Products
The Java Glossary
http://mindprod.com

Roedy Green

unread,
Jul 23, 2008, 6:55:11 AM7/23/08
to
On Wed, 23 Jul 2008 10:41:27 GMT, Roedy Green
<see_w...@mindprod.com.invalid> wrote, quoted or indirectly quoted
someone who said :

>StringBuilder temp = new StringBuilder();


>temp.append( hello );
>temp.append( world );
>s = temp.toString();

I wonder if it would be worth it for a compiler to try to guess a good
initial value for StringBuilder by computing the pieces first,
gathering their lengths and summing them for these hidden String
builds.

Thomas Fritsch

unread,
Jul 23, 2008, 7:17:08 AM7/23/08
to
Roedy Green wrote:
[...]

> String s = hello + world;
>
> is effectively the same as:
>
> StringBuilder temp = new StringBuilder();
> temp.append( hello );
> temp.append( world );
> s = temp.toString();
To be a bit more exact, it is the same as:

String s = (new StringBuilder(hello)).append(world).toString();

--
Thomas

Lasse Reichstein Nielsen

unread,
Jul 23, 2008, 7:29:46 AM7/23/08
to
stef <stef.pe...@gmail.com> writes:

> Silly question, but if - internally speaking- the java compiler
> replace the "String" class with "StringBuffer",

It doesn't, so the rest of the question is moot.

> what is the real purpose of "String" ? (except shorter keyword and,
> may be, when who do static stuff like String s ="hello "+"world")

The place where the compiler might use StringBuffer (or StringBuilder
in Java 5+) is in concatenations. I.e., in the above, it might create
code equivalent to:
String s = new StringBuilder("hello ").append("world").toString();
(In this particular case it'll probably just concatenate the two
literal strings at compile time, though).

/L
--
Lasse Reichstein Holst Nielsen
DHTML Death Colors: <URL:http://www.infimum.dk/HTML/rasterTriangleDOM.html>
'Faith without judgement merely degrades the spirit divine.'

Eric Sosman

unread,
Jul 23, 2008, 9:03:13 AM7/23/08
to

Is that a recent change? I seem to recall seeing
something more like

String s = (new StringBuilder())
.append(hello).append(world).toString();

... which is closer to Roedy's description. (Of course, in
Days Of Yore it was StringBuffer instead of StringBuilder.)

--
Eric Sosman
eso...@ieee-dot-org.invalid

Thomas Fritsch

unread,
Jul 23, 2008, 9:52:32 AM7/23/08
to
Doing "javap -c ..." with Java 1.5 and 1.6 I get:
String s =
(new StringBuilder(String.valueOf(hello))).append(world).toString();

With Java 1.4 I get:
String s =
(new StringBuffer(String.valueOf(hello))).append(world).toString();

--
Thomas

Roedy Green

unread,
Jul 23, 2008, 12:09:06 PM7/23/08
to
On Wed, 23 Jul 2008 09:03:13 -0400, Eric Sosman
<eso...@ieee-dot-org.invalid> wrote, quoted or indirectly quoted
someone who said :

> Is that a recent change? I seem to recall seeing


>something more like
>
> String s = (new StringBuilder())
> .append(hello).append(world).toString();
>
>... which is closer to Roedy's description. (Of course, in
>Days Of Yore it was StringBuffer instead of StringBuilder.)

Here are three decompilations with Javap from JDK 1.6.0_07 which
should settle the matter. The important point is concatenation makes
no attempt to optimise the size of the StringBuilder, even for the
simplest cases.

Showing building a String with StringBuilder.

final StringBuilder sb = new StringBuilder( 1024 );
sb.append( "<table class=\"borderless\" summary=\"" );
sb.append( title );
sb.append( " art print\"><tbody>\n" );

11: new #13; //class java/lang/StringBuilder
14: dup
15: sipush 1024
18: invokespecial #14; //Method
java/lang/StringBuilder."<init>":(I)V
21: astore 6
23: aload 6
25: ldc #15; //String <table class=\"borderless\" summary=\"
27: invokevirtual #16; //Method
java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
30: pop
31: aload 6
33: aload_1
34: invokevirtual #16; //Method
java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
37: pop
38: aload 6
40: ldc #17; //String art print\"><tbody>\n
42: invokevirtual #16; //Method
java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;

-------------------------------

two literals with concatenation, and no estimate for StringBuilder
size.

return "PostScript " + "(&iexcl;) exclamdown";

// combined at compile time
1326: ldc #89; //String PostScript (&iexcl;) exclamdown
1328: areturn

-------------------------------------------

concatenation involving literals, variables and constants:

return "needs Java " + version + " or later, version " +
JRE_FULL_VERSION + " recommended";

creates a StringBuilder with default size.
Note that even though JRE_FULL_VERSION is a public static final
String, the concatenations of literas before and after are NOT done at
compile time.

9: new #17; //class java/lang/StringBuilder
12: dup
13: invokespecial #18; //Method
java/lang/StringBuilder."<init>":()V
16: ldc #19; //String needs Java
18: invokevirtual #20; //Method
java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
21: aload_0 [ version is a parm passed to this method ]
22: invokevirtual #20; //Method
java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
25: ldc #21; //String or later, version
27: invokevirtual #20; //Method
java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
30: getstatic #22; //Field
com/mindprod/htmlmacros/SunJDKandJREVersions.JRE_FULL_VERSION:Ljava/lang/String;
33: invokevirtual #20; //Method
java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
36: ldc #23; //String recommended
38: invokevirtual #20; //Method
java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
41: invokevirtual #24; //Method
java/lang/StringBuilder.toString:()Ljava/lang/String;
44: areturn

The append method chosen returns a pointer to the StringBuilder, so
you don't have to manually dup it at each stage. invokeVirtual
consumes it..

so I would say that:

return "needs Java " + version + " or later, version " +
JRE_FULL_VERSION + " recommended";

compiles effectively to:

StringBuilder temp = new StringBuilder( /* default size */ );
// temp in on stack, not stack frame.
return temp.append( "needs Java " )
.append ( version )
.append ( " or later, version " )
.append( JRE_FULL_VERSION )
.append( " recommended")

Eric Sosman

unread,
Jul 23, 2008, 12:25:43 PM7/23/08
to

That's very odd. Using Java 1.6.0_05 on

String join(String hello, String world) {
return hello + world;
}

... I got

0: new #2; //class java/lang/StringBuilder
3: dup
4: invokespecial #3; //Method java/lang/StringBuilder."<init>":()V
7: aload_1
8: invokevirtual #4; //Method
java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
11: aload_2
12: invokevirtual #4; //Method
java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
15: invokevirtual #5; //Method
java/lang/StringBuilder.toString:()Ljava/lang/String;
18: areturn

... which is to say

return
(new StringBuilder()).append(hello).append(world).toString();

Wondering whether the code varied with the types of the concatenated
operands, I tried it with String+String, String+int, and int+String
with the same result all three times. I wonder what gives us such
different outcomes.

--
Eric....@sun.com

Mark Space

unread,
Jul 23, 2008, 12:33:34 PM7/23/08
to
Roedy Green wrote:
> On Wed, 23 Jul 2008 10:41:27 GMT, Roedy Green
> <see_w...@mindprod.com.invalid> wrote, quoted or indirectly quoted
> someone who said :
>
>> StringBuilder temp = new StringBuilder();
>> temp.append( hello );
>> temp.append( world );
>> s = temp.toString();
>
> I wonder if it would be worth it for a compiler to try to guess a good
> initial value for StringBuilder by computing the pieces first,
> gathering their lengths and summing them for these hidden String
> builds.

Why guess when you can profile? What if the compiler added some extra
variables:

class Something {
private static int temp$$totals = 16;
private static int temp$$runs = 1;

void myMethod() {
StringBuilder temp = new StringBuilder( temp$$totals/temp$$runs );
temp.append( "Hello " );
temp.append( "world!\n" );
String s = temp.toString();
if( s.length() + temp$$totals > 0 ) {
temp$$totals += s.length();
temp$$runs++;
}
}
}

That would be a neat addition to JIT compiled code. Alternately you
could use the maximum value for s.length() instead of the average if you
really wanted an aggressive StringBuilder. Or something in between the
average value and the maximum.

average + (maximum - average) * 0.8f; // or so.


Mike Schilling

unread,
Jul 23, 2008, 1:41:46 PM7/23/08
to
Lasse Reichstein Nielsen wrote:
> stef <stef.pe...@gmail.com> writes:
>
>> Silly question, but if - internally speaking- the java compiler
>> replace the "String" class with "StringBuffer",
>
> It doesn't, so the rest of the question is moot.
>
>> what is the real purpose of "String" ? (except shorter keyword and,
>> may be, when who do static stuff like String s ="hello "+"world")
>
> The place where the compiler might use StringBuffer (or
> StringBuilder
> in Java 5+) is in concatenations. I.e., in the above, it might
> create
> code equivalent to:
> String s = new StringBuilder("hello ").append("world").toString();
> (In this particular case it'll probably just concatenate the two
> literal strings at compile time, though).

Yes. So a better example might be:

return "The answer is: " + value;

which would generate bytecode equivalent to:

return new StringBuilder("The answer is:
").append(value).toString();


Arne Vajhøj

unread,
Jul 23, 2008, 7:35:52 PM7/23/08
to
Lasse Reichstein Nielsen wrote:
> stef <stef.pe...@gmail.com> writes:
>
>> Silly question, but if - internally speaking- the java compiler
>> replace the "String" class with "StringBuffer",
>
> It doesn't, so the rest of the question is moot.
>
>> what is the real purpose of "String" ? (except shorter keyword and,
>> may be, when who do static stuff like String s ="hello "+"world")
>
> The place where the compiler might use StringBuffer (or StringBuilder
> in Java 5+) is in concatenations. I.e., in the above, it might create
> code equivalent to:
> String s = new StringBuilder("hello ").append("world").toString();
> (In this particular case it'll probably just concatenate the two
> literal strings at compile time, though).

So true.

I fear we have another myth being born.

Arne

Roedy Green

unread,
Jul 24, 2008, 7:24:59 AM7/24/08
to

On Wed, 23 Jul 2008 12:25:43 -0400, Eric Sosman <Eric....@sun.com>

wrote, quoted or indirectly quoted someone who said :

>> With Java 1.4 I get:


>> String s =
>> (new StringBuffer(String.valueOf(hello))).append(world).toString();
>
> That's very odd. Using Java 1.6.0_05 on

1.4 to 1.6_05 gave plenty of time for Sun to make a minor tweak like
that.

Eric Sosman

unread,
Jul 24, 2008, 8:30:33 AM7/24/08
to
Roedy Green wrote:
> On Wed, 23 Jul 2008 12:25:43 -0400, Eric Sosman <Eric....@sun.com>
> wrote, quoted or indirectly quoted someone who said :
>
>>> With Java 1.4 I get:
>>> String s =
>>> (new StringBuffer(String.valueOf(hello))).append(world).toString();
>> That's very odd. Using Java 1.6.0_05 on
>
> 1.4 to 1.6_05 gave plenty of time for Sun to make a minor tweak like
> that.

Yes, but the oddity is that Thomas Fritsch (attribution
snipped above) gets different generated code from "Java 1.6"
than "Java 1.6.0_05" gives me. I'm at a loss to understand
the different behavior.

--
Eric Sosman
eso...@ieee-dot-org.invalid

Lew

unread,
Jul 25, 2008, 1:39:05 AM7/25/08
to
Lasse Reichstein Nielsen wrote:
>> (In this particular case it'll probably just concatenate the two
>> literal strings at compile time, though).

It has to, by JLS 15.28, "Constant Expression".
<http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#5313>.

--
Lew

Mike Schilling

unread,
Jul 25, 2008, 2:55:21 AM7/25/08
to

It could generate

String s = "Hello" + :"World";

as

String s = ("Hello".concat("World")).intern();

That would be really silly, but not so far as I can see illegal.


Lew

unread,
Jul 25, 2008, 8:35:35 AM7/25/08
to

These are labeled *compile-time* constants in the JLS, so, yes, it would be
illegal.

--
Lew

Mike Schilling

unread,
Jul 25, 2008, 12:44:20 PM7/25/08
to

But "compile-time constant" is a description of behavior, not
implementation.


Lew

unread,
Jul 25, 2008, 1:44:27 PM7/25/08
to
"Mike Schilling" wrote:
> But "compile-time constant" is a description of behavior, not
> implementation.

The behavior that it describes is that the concatenation occurs at
compile time. That's why it's called a "compile-time" constant. Thus
it precludes a run-time implementation.

From the JLS:
> "This is a " + // actually a string-valued constant expression,
> "two-line string" // formed from two string literals

And:
> We call a variable, of primitive type or type String, that is final and
> initialized with a compile-time constant expression (§15.28) a constant
> variable. Whether a variable is a constant variable or not may have
> implications with respect to class initialization (§12.4.1), binary
> compatibility (§13.1, §13.4.9) and definite assignment (§16).

In order to fulfill the semantic requirements of a compile-time
constant, the evaluation pretty much has to happen, well, at compile
time.

--
Lew

Message has been deleted
0 new messages