While browsing Java sources, I came accross an interesting code fragment that I thought I would share with you. This piece of code formats an integer array to string. I felt that the way the for loop is structured is very unusual. I wrote a similar method to compare our approaches. In this article I present both these versions.
Problem
We have to return a string representation of the contents of the specified array. The string representation consists of a list of the array's elements, enclosed in square brackets ("[]"). Adjacent elements are separated by the characters ", " (a comma followed by a space). Elements are converted to strings as by String.valueOf(char). Returns "null" if a is null.
For example: int[] a = = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
the return would be: [1, 2, 3, 4, 5, 6, 7, 8, 9]
JDK Version
Notice the for loop in the line 13 does not have a terminating check. The code for conditional formatting at the end of array (line 15) and return is interesting too.
//
// The following code is from JDK - java.util.Arrays.toString()
//
public static String toString(int[] a) {
if (a == null)
return "null";
int iMax = a.length - 1;
if (iMax == -1)
return "[]";
StringBuilder b = new StringBuilder();
b.append('[');
for (int i = 0; ; i++) {
b.append(a[i]);
if (i == iMax)
return b.append(']').toString();
b.append(", ");
}
}
My Version
public static String toStringMyVersion(int[] a) {
if (a == null) {
return "null";
}
if (a.length == 0) {
return "[]";
}
StringBuffer sb = new StringBuffer("[");
int size = a.length;
for (int x=0; x < size-1; x++) {
sb.append(a[x]).append(", ");
}
sb.append(a[size-1]).append("]");
return sb.toString();
}
If you liked this article then please vote for this article by clicking on the green up arrow.
Your feedback is most valuable. Please use 'comments' or an e-mail to saimatam (at) yahoo (dot) com
Nitin - All your comments are there. I did not delete any of them. What is the bug that you are talking about?
Thank you everyone for the comments and the lively discussion. After all your suggestions, the code now is in great shape :-)
regards,
Sai Matam
Posted by: Sai Matam | 05/05/2012 at 09:34 PM
My earlier comment got deleted ! it is easy (well not much easy when you get excited about improvements) to find the bug :)
Posted by: Nitin | 05/04/2012 at 10:08 PM
Code in JDK and by nicerobot is 'correct', all other versions presented here have bug !
Be careful while doing so called optimization ;)
Posted by: Nitin | 05/03/2012 at 10:25 PM
Just a little improvement: don't compute size -1 every time but only once. For the rest is perfect.
public static String toStringMyOwnVersion(int[] a) {
if (a == null) {
return "null";
}
if (a.length == 0) {
return "[]";
}
StringBuilder sb = new StringBuilder();
db.append('[');
int size = a.length-1;
for (int x=0; x < size; x++) {
sb.append(a[x]).append(", ");
}
sb.append(a[size]).append(']');
return sb.toString();
}
Posted by: Luca Garulli | 05/03/2012 at 02:24 PM
// You should always pre-allocate StringBuilders.
// A loops condition and increment should always be as simple as possible.
public static String arrayToString(int[] a) {
if (a == null) {
return "null";
}
int size = a.length;
if (size == 0) {
return "[]";
}
StringBuilder sb
= new StringBuilder(size*4+2)
.append('[').append(a[0]);
for (int x=1; x < size; x++) {
sb.append(", ").append(a[x]);
}
return sb.append(']').toString();
}
Posted by: nicerobot | 05/03/2012 at 01:46 PM
Use Google Guava.
Posted by: Sumit | 05/03/2012 at 08:16 AM
This is too much work. Since your separator is "," instead of ", ", you cannot use java.lang.Arrays.toString(int[]). But you can save yourself a lot of code with this:
public static String toCommaSeparatedString(int[] a) {
if (a == null) {
return null;
}
String separator = "";
StringBuilder b = new StringBuilder();
b.append("[");
for(int i: a) {
b.append(separator);
b.append(i);
separator = ",";
}
b.append("]");
return b.toString();
}
There's only one if statement. In fact, I've seen a library, I think from Israel, with a Separator class:
public class Separator {
private final String separator;
private String current = "";
public Separator(final String separator) {
this.separator = separator;
}
public String toString() {
String s = current;
current = separator;
return s;
}
}
Now, the code becomes:
public static String toCommaSeparatedString(int[] a) {
if (a == null) {
return null;
}
Separator separator = new Separator(",");
StringBuilder b = new StringBuilder();
b.append("[");
for(int i: a) {
b.append(separator);
b.append(i);
}
b.append("]");
return b.toString();
}
I'd be careful about using Separator though; using an IDE and debugging might trigger the toString() method early.
Posted by: Eric Jablow | 05/03/2012 at 08:15 AM
Your version could be improved somewhat by using StringBuilder instead of StringBuffer. The latter is thread-safe, which isn't necessary when your buffer is used entirely within a single method.
Posted by: David Karr | 05/03/2012 at 08:08 AM
Personally, I would prefer your version, because it is clearer in particular for the return part.
But my own version would be the following, keeping some append(char) from the JDK version as general tip on performance:
public static String toStringMyOwnVersion(int[] a) {
if (a == null) {
return "null";
}
if (a.length == 0) {
return "[]";
}
StringBuilder sb = new StringBuilder();
sb.append('[');
int size = a.length;
for (int x=0; x < size-1; x++) {
sb.append(a[x]).append(", ");
}
sb.append(a[size-1]).append(']');
return sb.toString();
}
What is sure is that they all work well, and they probably have negligible performance differences.
Posted by: evernat | 05/03/2012 at 07:18 AM