Performance/efficiency question

E

Edward A Thompson

Is the A) and less efficiecnt than B)? Should I be using
StringBuffers instead?

String value23 = "23";

A:

String a = "line 1:" + "twenty three = " + value23 ;

B:

String = "line 1:twenty three = " + value23 ;

I m using something like A) for readability when the Strings I am
assigning are long so that the program is readable (for instance,
building a lon SQL statement), but I don't want to imapct actual
performance. I know String buffers are better for dynamic Strings,
but wasn't sure how the compiler would respond to the above, IE are
the additions in the string assignment accomplished at run time or
compile time?

If at run time, won't each addition dictate and actaulareallocation of
the String? If compile time, won't it be smart enough to only
allocate once?

Feedback appreciated before I get to farther in right/wrong design...
 
H

Hugo Pragt

If performance is an issue I would go for as little object creation as
possible.
Especially String objects are expensive
So, if it is at all possible create some static strings/stringbuffers. They
get created only once per class
If this is not possible try to place the object creation (new String)
outside loops (for nexts, while wend etc)
If this is not possible try not to use String objects but StringBuffer
objects (they are less expesive)
Avoid things like:
StringBuffer sb=new StringBuffer("some text");
Why? whell "some text" will become a new String object so that it can be
passed as a parameter. After the (expensive) String object is created the
(less expensive) StringBuffer object is created using the String parameter.
And when that is done your (expensive) String parameter object is thrown
away. Rsulting costs are higher than just creating a new String object!
Thus B is less expensive than A but can be made even more performant...

Hugo

P.s. There are some nice books out there, you should try to get a hold on
one.
 
J

Jim Sculley

Edward said:
Is the A) and less efficiecnt than B)? Should I be using
StringBuffers instead?

String value23 = "23";

A:

String a = "line 1:" + "twenty three = " + value23 ;

B:

String = "line 1:twenty three = " + value23 ;

I m using something like A) for readability when the Strings I am
assigning are long so that the program is readable (for instance,
building a lon SQL statement), but I don't want to imapct actual
performance. I know String buffers are better for dynamic Strings,
but wasn't sure how the compiler would respond to the above, IE are
the additions in the string assignment accomplished at run time or
compile time?

Concatenation of compile time constant String literals occurs at compile
time. The above two snippets will produce identical (but suboptimal)
bytecode:

public Test();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: aload_0
5: ldc #2; //String 23
7: putfield #3; //Field value23:Ljava/lang/String;
10: aload_0
11: new #4; //class StringBuffer
14: dup
15: invokespecial #5; //Method java/lang/StringBuffer."<init>":()V
18: ldc #6; //String line 1:twenty three =
20: invokevirtual #7; //Method
java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
23: aload_0
24: getfield #3; //Field value23:Ljava/lang/String;
27: invokevirtual #7; //Method
java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
30: invokevirtual #8; //Method
java/lang/StringBuffer.toString:()Ljava/lang/String;
33: putfield #9; //Field a:Ljava/lang/String;
36: return

}

I say suboptimal, because the StringBuffer class is being used
internally to do the final concatenation with the 'value23' variable.
If you mark that variable as 'final', you get much nicer bytecode:


public Test();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: aload_0
5: ldc #2; //String 23
7: putfield #3; //Field value23:Ljava/lang/String;
10: aload_0
11: ldc #4; //String line 2:twenty three = 23
13: putfield #5; //Field a:Ljava/lang/String;
16: return
}

Note that StringBuffer objects are created.
If at run time, won't each addition dictate and actaulareallocation of
the String? If compile time, won't it be smart enough to only
allocate once?

Only if you give the compiler sufficient information. If your variables
pointing to String literals represent immutable constants, mark them as
such using 'final' and the compiler will allocate them as efficiently as
possible.

Jim S.
 
D

Dario

Edward said:
Is the A) and less efficiecnt than B)? Should I be using
StringBuffers instead?

String value23 = "23";

A:

String a = "line 1:" + "twenty three = " + value23 ;

B:

String = "line 1:twenty three = " + value23 ;


For what I known "line 1:" + "twenty three = "
is translated in "line 1:twenty three = " by the compiler.

- Dario
 
E

Ed Thompson

Jim said:
Concatenation of compile time constant String literals occurs at compile
time. The above two snippets will produce identical (but suboptimal)
bytecode:

public Test();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: aload_0
5: ldc #2; //String 23
7: putfield #3; //Field value23:Ljava/lang/String;
10: aload_0
11: new #4; //class StringBuffer
14: dup
15: invokespecial #5; //Method java/lang/StringBuffer."<init>":()V
18: ldc #6; //String line 1:twenty three =
20: invokevirtual #7; //Method
java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
23: aload_0
24: getfield #3; //Field value23:Ljava/lang/String;
27: invokevirtual #7; //Method
java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
30: invokevirtual #8; //Method
java/lang/StringBuffer.toString:()Ljava/lang/String;
33: putfield #9; //Field a:Ljava/lang/String;
36: return

}

I say suboptimal, because the StringBuffer class is being used
internally to do the final concatenation with the 'value23' variable.
If you mark that variable as 'final', you get much nicer bytecode:


public Test();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: aload_0
5: ldc #2; //String 23
7: putfield #3; //Field value23:Ljava/lang/String;
10: aload_0
11: ldc #4; //String line 2:twenty three = 23
13: putfield #5; //Field a:Ljava/lang/String;
16: return
}

Note that StringBuffer objects are created.



Only if you give the compiler sufficient information. If your variables
pointing to String literals represent immutable constants, mark them as
such using 'final' and the compiler will allocate them as efficiently as
possible.

Jim S.

I just used value23 as an example. I would use final if I could,
but in reality it is set at run time by a function call.

But it sounds like I am OK with the +'s with constnat strings at least?

BTW, How did you get the decompiled byte code?
 
C

Christophe Vanfleteren

Hugo said:
If performance is an issue I would go for as little object creation as
possible.

Good advice
Especially String objects are expensive

There is nothing specially expensive about creating a String object.
So, if it is at all possible create some static strings/stringbuffers.
They get created only once per class

If you have a String member variable that gets initialised to some known
value at compile time, that String will be entered into the constant pool,
and all instances of the class will be using the same String instance
anyway (which has no potential side effects since a String is immutable).

You can see this with the following code:

public class TestString {
//known at compiletime
private String testKnown = "test";
//unkonw at compiletime
private String testUnknown = "tester".substring(0,4);

public static void main(String[] args) {
TestString a = new TestString();
TestString b = new TestString();
if(a.testKnown == b.testKnown) {
System.out.println("same String instance reused");
}
if(a.testUnknown != b.testUnknown) {
System.out.println("other String instance used");
}
}
}

If you have a member variable that will always be the same for all
instances, you should always use a static variable anyway, wether it is a
String or not.
If this is not possible try to place the object creation (new String)
outside loops (for nexts, while wend etc)

The import thing in loops, is that you should avoid "changing" (or appending
to) Strings in them (you can't really change a String, since they're
immutable. You can only create a new one with the modified contents of the
previuos one.

What happens when you do something like

myString += "another string" in a loop, the following code is generated in
each iteration:

myString = new StringBuffer(myString).append("another String").toString();

So it is more efficient to just create the StringBuffer just once outside of
the loop, and directly append to that. Less objects (garbage) get created
that way.
If this is not possible try not to use String objects but StringBuffer
objects (they are less expesive)
Avoid things like:
StringBuffer sb=new StringBuffer("some text");
Why? whell "some text" will become a new String object so that it can be
passed as a parameter. After the (expensive) String object is created the
(less expensive) StringBuffer object is created using the String

It might as well be possible that creating a StringBuffer is more expensive
than creating a String, because a bigger char array will need to be
allocated when creating a Stringbuffer. Looking at the JDK source, it seems
that when creating a StringBuffer, you always have an array of String
length (0 if using default constructor) + 16 allocated.
 
E

Ed Thompson

Dario said:
For what I known "line 1:" + "twenty three = "
is translated in "line 1:twenty three = " by the compiler.

- Dario
That's what I wanted to hear. I am using the + like a line continuation
for Strings
 
E

Ed Thompson

Note that StringBuffer objects are created.

If I read this right, If I am going to set a String to a constant +
variable, where the variable is known at run time, I should just use
StringBuffer in the first place?

But if the String is just a literal (even literals concatendated with
+'s), String is more efficient

Would you concur?
 
J

Jim Sculley

Ed said:
I just used value23 as an example. I would use final if I could,
but in reality it is set at run time by a function call.
OK.

But it sounds like I am OK with the +'s with constnat strings at least?

Yes.

BTW, How did you get the decompiled byte code?

javap -c NameOfYourCompiledClass


Jim S.
 
J

Jim Sculley

Ed said:
If I read this right, If I am going to set a String to a constant +
variable, where the variable is known at run time, I should just use
StringBuffer in the first place?

If you are initializing many Strings then, yes. The compiler will
create a new StringBuffer object for each variable. You can write the
code such that the same StringBuffer is used repeatedly which might be
more efficient.
But if the String is just a literal (even literals concatendated with
+'s), String is more efficient

Would you concur?

Yes. No StringBuffer is created by the compiler in that situation.

Jim S.
 
T

Tony Morris

If you place this statement inside a for loop, you'll face performance
problems by as much as 15000% (during my benchmarks anyway) - I assume this
is due to some optimisation by JIT.

Discussion with Neal Gafter (author of the Sun compiler) reveals that the
lack of performance caused by "misusing" the String concatenation operator
(generally, where one or more operands are not final or literal) is the
responsibility of the compiler/runtime developer. It is hinted that this
performance hit will be alleviated in the upcoming 1.5 release.

Some benchmarks I did a while ago:
http://www.xdweb.net/~dibblego/javafaq/javafaq.html#q33

--
Tony Morris
(BInfTech, Cert 3 I.T., SCJP[1.4], SCJD)
Software Engineer
IBM Australia - Tivoli Security Software
(2003 VTR1000F)
 
C

Chris Smith

Ed and Jim,

Sorry for jumping in this late. I'm not getting half the posts in this
thread for some reason.

Jim said:
[...]

Ed said:
But it sounds like I am OK with the +'s with constnat strings at least?

You are, in fact, fine with plain string concatenation for non-constant
variables as well, in the situation given here. Doing so will create a
StringBuffer behind the scenes, which is the best way to go. (*)

The well-publicized problems with string concatenation arise when you
are repeating concatenation to a String in several different statements,
and in particular when you concatenate many times successively to the
same String in a loop.

[*] Note that the bytecode Jim posted isn't necessarily ideal for the
case of concatenating non-constant data. His bytecode was the
equivalent of:

StringBuffer sb = new StringBuffer();
sb.append("line 1:twenty three = ");
sb.append(value23);

You may be able to get better results from:

StringBuffer sb = new StringBuffer("line 1:twenty three = ");
sb.append(value23);

However, the difference will be negligible, and I can't guarantee
that the second code will always be faster. It's likely to depend
on the length of the String literal and of the text representation
of the non-constant value you are appending. If you know the
length of the non-constant value, you can almost certainly do
at least as well or minutely better with:

StringBuffer sb = new StringBuffer(24);
sb.append("line 1:twenty three = ");
sb.append(value23);

Where '24' is the total length of the resulting String (the constant
and non-constant portions. However, this duplicates information and
is likely to get out of date, and you're rather unlikely to ever
notice better performance from this. So, I'd avoid it if at all
possible.

--
www.designacourse.com
The Easiest Way to Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads

Loop Efficiency 17
Arguing efficiency. Arg! 5
Efficiency of s///e? 9
Java performance 28
struct initializer efficiency and portability 1
valarray performance 11
efficiency question 1
performance question 129

Members online

No members online now.

Forum statistics

Threads
473,764
Messages
2,569,567
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top