Is there a faster method than StringBuilder to maximize the concatenation of strings 9-10 steps long?

I have this code to instantiate some array elements:

StringBuilder sb = new StringBuilder(); private RatedMessage joinMessage(int step, boolean isresult) { sb.delete(0, sb.length()); RatedMessage rm; for (int i = 0; i <= step; i++) { if (mStack[i] == null) continue; rm = mStack[i].getCurrentMsg();// msg is built upfront, this just returns, it a getter method call if (rm == null || rm.msg.length() == 0) continue; if (sb.length() != 0) { sb.append(", "); } sb.append(rm.msg); } rm.msg=sb.toString(); return rm; } 

It is important that the array contains a maximum of 10 elements, so it is not very much.

My trace output tells me that this method is called 18864 times, 16% of the execution time was spent in this method. Can I optimize more?

+6
java stringbuilder concatenation
source share
11 answers

some ideas:

1) Do you initialize a StringBuilder with an estimated maximum capacity? This can save the time spent redistributing and copying the internal array.

2) Perhaps you can add a trailing comma in the loop and avoid the string length condition inside the loop. Instead, add a single condition at the end of the method and remove the trailing comma, if necessary.

+3
source share

First of all, I will not reuse StringBuilder and always create a new instance. This will, of course, be faster, because it will allow the GC to use the heap area of ​​the younger generation.

Another little trick that eliminates at least one if statement is to rewrite your code as follows:

  String separator = ""; for (int i = 0; i <= step; i++) { ... sb.append(separator); sb.append(rm.msg); separator = ", "; } 
+5
source share

You can make the following change (showing only the differences):

  String separator = ""; for (int i = 0; i <= step; i++) { // ... sb.append(separator).append(rm.msg); separator = ", "; } 

It gets rid, if extra, if 9 times by adding an empty string once. You should measure if it helps at all with the data you use before you decide to save this change :-)

+1
source share

If your function should concatenate the elements of an array, why are you passing all these crazy values ​​and unused parameters?

 private string joinMessage( string[] myArray) { StringBuilder sbr = new StringBuilder(); for(int i = 0; i < myArray.Length; i++) { if(!string.IsNullOrEmpty(myArray[i]) { sbr.Append(myArray[i]); sbr.Append(",") } } return sbr.ToString(); } 
0
source share

First, take a step through each item on the stack, taking a total of all the lengths of the lines.

Then you can use

 sb.ensureCapacity(totalEndLength); 

The string constructor works like a list of arrays, so you can rebuild this array using most of your applications.

0
source share

A bit of mini optimization ... take a test comma outside the loop.

 private RatedMessage joinMessage(int step, boolean isresult) { sb.delete(0, sb.length()); for (int i = 0; i <= step; i++) { if (mStack[i] == null) continue; rm = mStack[i].getCurrentMsg(); if (rm == null || rm.msg.length() == 0) continue; sb.append(rm.msg).append(", "); } if (sb.length() > 2) { sb.delete(sb.length() - 2, 2); } return sb.toString(); } 

Other offers:

  • Make sure that when building a StringBuilder you set its initial length to a decent value
  • I'm not sure about the context of the rest of the code, but maybe you can make sure that mStack [i] is not null and mStack [i] .getCurrentMessage () is not null or empty - this will allow you to accept more if statements outside cycle.
0
source share

Have a separate copy of the mStack array with a string representation, initialized to an empty String by default, so your loop will look like this:

 String [] mStackCopy = new String[]{"","","","","","","","","","",}; // or mstackCopy = new String[mStack.length]; // for( int i = 0 ; i < mStackCopy.lenght ; i++ ) { mStack[i] = "" } 

Also create a StringBuilder with enough capacity:

 StringBuilder sb = new StringBuilder( 10000 );// 10k chars or whatever makes sense. 

So, when you need to create a message, you simply:

 for (int i = 0; i <= step; i++) { sb.append( mStackCopy[i] ); } 

And the empty parts will not cause a problem, because they are already empty:

You can even write it hard:

  sb.append( mStackCopy[0]); sb.append( mStackCopy[1]); sb.append( mStackCopy[2]); sb.append( mStackCopy[3]); sb.append( mStackCopy[4]); sb.append( mStackCopy[5]); sb.append( mStackCopy[6]); sb.append( mStackCopy[7]); sb.append( mStackCopy[8]); sb.append( mStackCopy[9]); 

But it will bring more pain than the relief in the future guaranteed.

When you add something to your mStack:

 MStack item = new MStack(); item.setCurrentMessage("Some message"); .... 

Just create a copy of the message and add "," already.

  addToMStack(int position, MStackItem item ) { mStack[position] = item; mStackCopy[position] = item.getCurrentMessage() + ", "; } 

And depending on the appearance of zeros (if its low) you can catch them

  addToMStack(int position, MStackItem item ) { if( item == null ) { return; } mStack[position] = item; try { mStackCopy[position] = item.getCurrentMessage() + ", "; } catch( NullPointerException npe ){} } 

What is terrifying

Or confirm it:

  addToMStack(int position, MStackItem item ) { if( item == null ) { return; } mStack[position] = item; mStackCopy[position] = item.getCurrentMessage() + ", "; } 

I'm sure your method does something else that you are not showing us. Probably the reason is here.

In addition, 16% is not so bad if 100% is 1 second.

0
source share

If your mStack is a collection instead of an array, you can simply do mStack.toString() , which will print the readable string of the array. It may be easier than writing your own.

0
source share

16% of the runtime in this method, including or excluding called methods? Calling getCurrentMsg () can be a hidden issue if it creates many objects.

In addition, I suggest pulling out all the necessary lines from your stack, and then calling

StringUtils.join(myStrings, ", ")

using the Apocal commons library . Try relying on proven code for these low-level things, rather than optimizing it every day. In the end, this will give you the best optimization results, because you can focus on the big picture (i.e. the overall design of your software).

0
source share

Sometimes there is nothing to optimize. I think this is one such case. You can try to shave off an instruction or two, maybe, but you won’t get it much faster in principle.

I think the only thing that needs to be optimized is to consider why you call it 18864 times and whether some of these calls can be avoided at all. Maybe some of them are not needed, or maybe you can cache the result in some cases.

0
source share

Use StringBuilder + StringUtils from Apache Commons Lang. Looping with a delimited String and chomping is what StringUtils is!

 private RatedMessage joinMessage(int step, boolean isresult) { StringBuilder builder = new StringBuilder(); for (int i = 0; i <= step; i++) { WhateverTypeIsFromMStackVariable stackVariable = mStack[i]; String message = getMessage(stackVariable); if(StringUtils.isNotEmpty(message)) { builder.append(message).append(", "); } } RatedMessage rm = new RatedMessage(); rm.msg = StringUtils.chomp(builder.toString(), ", "); return rm; } private static String getMessage(WhateverTypeIsFromMStackVariable stackVariable) { if(stackVariable != null) { RatedMessage message = stackVariable.getCurrentMsg(); if(message != null) { return message.msg; } } return null; } 

Apache Commons Lang is here: http://commons.apache.org/lang/

0
source share

All Articles