Click here to Skip to main content
Licence CPOL
First Posted 7 Apr 2004
Views 91,176
Bookmarked 7 times

Java Generic Code - Convert Array Contents to a String in a Generic Way

By | 7 Apr 2004 | Article
Presenting a generic way to convert Array contents to Strings

Introduction

In this article, I hope to start a series of articles discussing Java Generic Code. I will start with a problem that although easily solved, reared up its ugly head in many code sessions with my peers. ;)

Java Generic Code - Convert Array Contents to a String in a Generic Way

Imagine that you have the following code:

public static void main(String[] args) {
  Object[] arrayList = {
    new int[] {0, 1, 2 ,3},
    new double[] {0.1d, 1.0d, 3.2d ,3.5d},
    new java.awt.Color[] {java.awt.Color.BLACK, java.awt.Color.WHITE},
    new boolean[] {true, false, true, true, false, false}
  };
  for (int i = 0; i < arrayList.length; i++) {
    System.out.println("Array[" + (i + 1) + "] = " + arrayToString(arrayList[i]));
  }
}

And somehow (due to the "miracle" of the arrayToString() method) the output looks like this:

Array[1] = [0, 1, 2, 3] 
Array[2] = [0.1, 1.0, 3.2, 3.5] 
Array[3] = [java.awt.Color[r=0,g=0,b=0], java.awt.Color[r=255,g=255,b=255]] 
Array[4] = [true, false, true, true, false, false] 

You'd be happy with such a method because it means you can now easily get the contents of any Java Array object, formatted as a String using one simple method, instead of repeatedly writing code to iterate the Arrays and process each item individually.

Why This is Actually Important

This may sound like a trivial problem, but let me emphasize that a lot of programmers working in teams will attempt to write their own code to solve this. Having many components carry out the same functionality is a waste, and be warned that while some programmers will get it right and won't have any bugs in solving this problem, other programmers may accidentally write a method to display an Array's contents suffering from bugs! I actually wasted 20 minutes, together with another programmer, because his debug code did not display the LAST item in an Array object, causing us to think the last item actually was never sent properly.

NOT FUNNY! :(

On With the Show

Such a method does not exist in the JDK but it is very short and easy to understand; examine the following code:

 1  public static String arrayToString(Object array) {
 2    if (array == null) {
 3      return "[NULL]";
 4    } else {
 5      Object obj = null;
 6      if (array instanceof Hashtable) {
 7        array = ((Hashtable)array).entrySet().toArray();
 8      } else if (array instanceof HashSet) {
 9        array = ((HashSet)array).toArray();
10      } else if (array instanceof Collection) {
11        array = ((Collection)array).toArray();
12      }
13      int length = Array.getLength(array);
14      int lastItem = length - 1;
15      StringBuffer sb = new StringBuffer("[");
16      for (int i = 0; i < length; i++) {
17        obj = Array.get(array, i);
18        if (obj != null) {
19          sb.append(obj);
20        } else {
21          sb.append("[NULL]");
22        }
23        if (i < lastItem) {
24          sb.append(", ");
25        }
26      }
27      sb.append("]");
28      return sb.toString();
29    }
30  }

Let's examine the code in detail.

Lines 2-4

First off, we check if the array passed to us is null, if so, lines 2-3 will return "[NULL]" and we're done!

Lines 5-12

If the array is not null, then lines 6-12 make sure that if - by mistake? - we were handed a Hashtable/HashSet/Collection object, it will be properly converted to an array object for us!

Line 13

Here we use Java's Array class to generically retrieve the length of the array in question; this of course is needed because if you remember, we receive the array as an Object and not as a proper Array of any Java native type.

Lines 14-16

Calculate the index of the last item; create a StringBuffer to collect the text output; initiate a for-loop to go through all the items in the array.

Line 17

Here again, we use Java's Array class to generically retrieve the currently indexed item.

Line 18-26

Given the currently indexed item in the array, we either add the item's contents - as expressed by its toString() method - and add it to the StringBuffer, or if the current item is null, we add "[NULL]" to the StringBuffer to show there is nothing in this slot. At line 23, we check if the item was the last one, if it is not, line 24 will add a comma and a space so we can continue to build the text output properly.

Line 27-30

Now, we append a "]" character to the end of the StringBuffer, and return the whole text out of the StringBuffer back to our calling method.

I hope this little method will help, I know I have found it very helpful when I had to debug code that had a lot of different types of Array objects which were all to be printed, formatted into Java Exceptions and other interesting things which required the contents of the Array to be easily converted into a text String.

Enjoy.

History

  • 7th April, 2004: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Doron Barak

Web Developer

Canada Canada

Member



Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
Question?? PinmemberGreatGhoul18:41 13 Jan '10  
GeneralNested Arrays PinmemberDavy Boy5:35 12 Dec '05  
Nice work,
 
What would be a useful extension to this however, would be a type check on the obj (obj=Array.get(array, i);), to see if it is an array itself. If it is, then recurse this method, until you have no more arrays. (Of course, this would all fall down horribly if you had two arrays a1 and a2 where a1 = { a2 } and a2 = { a1 }), but it is a thought to maybe extend this further...
 
I have had a crack at the code to make some improvements... (kill me if they are cr@p!). The following code is untested, and thus may not compile work properly, but I've had a stab anyways.
 
What this code now does is outputs the contents of arrays inside the arrays, and deals with recursion issues that may be present. It also handles exceptions gracefully.
 
 1  public static String arrayToString(Object array) {
 2    return arrayToString(array, new HashSet());
 3  }
 4
 5  private static String arrayToString(Object array, Set setDone) {
 6    if (array == null) {
 7      return "[NULL]";
 8    } else {
 9      try {
10        Object obj = null;
11        if (array instanceof Hashtable) {
12          array = ((Hashtable)array).entrySet().toArray();
13        } else if (array instanceof Collection) {
14          array = ((Collection)array).toArray();
15        }
16        int length = Array.getLength(array);
17        setDone.add(array);
18        int lastItem = length - 1;
19        StringBuffer sb = new StringBuffer("[");
20        for (int i = 0; i < length; i++) {
21          obj = Array.get(array, i);
22          if (obj != null) {
23            try {
24/* nothing= */Array.getLength(obj);
25              if (!(setDone.contains(obj))) {
26                sb.append(arrayToString(obj, setDone));
27              }
28              else {
29                sb.append("[RECURSIVE:" + obj.toString() + "]");
30              }
31            }
32            catch (IllegalArgumentExcption e) {
33              sb.append(obj.toString());
34            }
35          } else {
36            sb.append("[NULL]");
37          }
38          if (i < lastItem) {
39            sb.append(", ");
40          }
41        }
42        sb.append("]");
43        return sb.toString();
44      }
45      catch (IllegalArgumentException e) {
46        return array.toString();
47      }
48    }
49  }
 
So what have I changed. Well, notably I have created a second method which does the hard work, and has two parameters, the array and a Set of arrays we have already outputted. The simple method on lines 1-3 calls the complex method with a new HashSet, to provide a simple interface and backwards compatibility to the previous implementation.
 
Lines 9, and 44-47 deal with the case where you are not passing an array to the method. As such the first time you call a method Array.xxxx with the object 'array', that isn't an array, it will throw an IllegalArgumentException. In this case I felt it would be neater to not throw the exception to the method that called this, but to handle gracefully, and just do a simple .toString().
 
Lines 11-15, I shortened down the tests by removing the test on HashSet. It is an instance of a Collection anyways, so it was more code than was necessary.
 
Line 17 adds the array we are wanting to get the string for, to the set of those we have already done .
 
Lines 23-34 deal with the case of arrays in arrays. Firstly, on lines 23 & 32 we are preparing ourselves for the case that the object obj is not an array. As yet, I have not been able to find a pretty method of determining whether an object is an array, so I have to rely on this ugly method. It does obviously incur a speed penalty, but as the orginal purpose for this method is to debug, I think we can afford the speed penalty. Line 24 is simply a check to see if we can throw an exception (if it isn't an array) or not (it is an array). Having safely gotten past the Array.getLength check, we know we have an array. What we now check on line 25, is if the set of those we have already done, doesn't contain the array we hold. If not, we recursively call this method on line 26. If we already have, then we output the statement [RECURSIVE: followed by the obj.toString() and a closing ], so that we know we have a recursive array, and some information about it.
 
If we didn't have an array in obj in lines 23-24, we would have thrown an IllegalArgumentException. In this case, we know we can simply output the obj.toString();
 
I have also used .toString() methods where it was being implictly called. Some people might miss what the implicit code is actually doing, so I added it for clarity.
 
Once again, thanks for the nice work, hope you can use my modifications.
 
Davy Boy Out...

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Mobile
Web04 | 2.5.120529.1 | Last Updated 8 Apr 2004
Article Copyright 2004 by Doron Barak
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid