Tuesday, November 30, 2010

Stringifying Java Arrays

J2SE 5 provided significant new language features that made Java significantly easier to use and more expressive than it had ever been. Although "big" new J2SE 5 features such as enums, generics, and annotations, there was a plethora of new APIs and methods that have made our lives easier ever since. In this post, I briefly look at two of my favorites when dealing with Java arrays: the Arrays.toString(Object[]) method and the Arrays.deepToString(Object[]) method.

The Arrays class has been around since JDK 1.2, but the methods for conveniently and simply converting arrays to a readable String including relevant array content without using Arrays.asList() were added with J2SE 5. Both Arrays.toString(Object[]) and Arrays.deepToString(Object[]) are static methods that act upon the arrays provided to them. The former, Arrays.toString(Object[]), is intended for single-dimension arrays while the latter, Arrays.deepToString(Object[]), is intended for multi-dimensional arrays. As my example later in this post will demonstrate, the multi-dimension deepToString will produce expected results even for single-dimension arrays. The two methods also provide easy and safe null handling, something that I appreciate.

The next code listing is for a simple demonstration class that demonstrates trying to put the contents of various types of Java arrays into a String format. The types of arrays demonstrated are a single dimension array, a double dimensional array representing multi-dimensional arrays of various sizes, and an array that is really just null. The three methods demonstrated for getting a String out of these three types of arrays are (1) simple Object.toString() on each array (implicitly in case of null array to avoid the dreaded NullPointerException), (2) Arrays.toString(Object[]), and (3) Arrays.deepToString(Object[]).

ArrayStrings.java
  1. package dustin.examples;  
  2.   
  3. import java.util.Arrays;  
  4. import static java.lang.System.out;  
  5.   
  6. /** 
  7.  * Simple demonstration of Arrays.toString(Object[]) method and the 
  8.  * Arrays.deepToString(Object[]) method. 
  9.  */  
  10. public class ArrayStrings  
  11. {  
  12.    /** 
  13.     * Demonstrate usage and behavior of Arrays.toString(Object[]). 
  14.     */  
  15.    private static void demonstrateArraysToString()  
  16.    {  
  17.       printHeader("Arrays.toString(Object[])");  
  18.       out.println(  
  19.            "Single Dimension Arrays.toString: "  
  20.          + Arrays.toString(prepareSingleDimensionArray()));  
  21.       out.println(  
  22.            "Double Dimension Arrays.toString: "  
  23.          + Arrays.toString(prepareDoubleDimensionArray()));  
  24.       out.println(  
  25.            "Null Array Arrays.toString: "  
  26.          + Arrays.toString(prepareNullArray()));  
  27.    }  
  28.   
  29.    /** 
  30.     * Demonstrate usage and behavior of Arrays.deepToString(Object[]). 
  31.     */  
  32.    private static void demonstrateArraysDeepToString()  
  33.    {  
  34.       printHeader("Arrays.deepToString(Object[])");  
  35.       out.println(  
  36.            "Single Dimension Arrays.deepToString: "  
  37.          + Arrays.deepToString(prepareSingleDimensionArray()));  
  38.       out.println(  
  39.            "Double Dimension Arrays.deepToString: "  
  40.          + Arrays.deepToString(prepareDoubleDimensionArray()));  
  41.       out.println(  
  42.            "Null Array Arrays.deepToString: "  
  43.          + Arrays.deepToString(prepareNullArray()));  
  44.    }  
  45.   
  46.    /** 
  47.     * Demonstrate attempting to get String version of array with simple toString() 
  48.     * call (not using Arrays class). 
  49.     */  
  50.    private static void demonstrateDirectArrayString()  
  51.    {  
  52.       printHeader("Object[].toString() [implicit or explicit]");  
  53.       out.println("Single Dimension toString(): " + prepareSingleDimensionArray().toString());  
  54.       out.println("Double Dimension toString(): " + prepareDoubleDimensionArray());  
  55.       out.println("Null Array toString(): " + prepareNullArray());  
  56.    }  
  57.   
  58.    /** 
  59.     * Prepare a single-dimensional array to be used in demonstrations. 
  60.     * 
  61.     * @return Single-dimensional array. 
  62.     */  
  63.    private static Object[] prepareSingleDimensionArray()  
  64.    {  
  65.       final String[] names = {"Aaron""Bianca""Charles""Denise""Elmer"};  
  66.       return names;  
  67.    }  
  68.   
  69.    /** 
  70.     * Prepare a double-dimension array to be used in demonstrations. 
  71.     * 
  72.     * @return Double-dimensional array. 
  73.     */  
  74.    private static Object[] prepareDoubleDimensionArray()  
  75.    {  
  76.       final Object[][] namesAndAges = {  
  77.          {"Aaron"10}, {"Bianca"25}, {"Charles"32}, {"Denise"29}, {"Elmer"67}};  
  78.       return namesAndAges;  
  79.    }  
  80.   
  81.    /** 
  82.     * Prepare a null array. 
  83.     * 
  84.     * @return Array that is really null. 
  85.     */  
  86.    private static Object[] prepareNullArray()  
  87.    {  
  88.       return null;  
  89.    }  
  90.   
  91.    /** 
  92.     * Print simple header to standard output with provided header string. 
  93.     * 
  94.     * @param headerString Text to be included in simple header. 
  95.     */  
  96.    public static void printHeader(final String headerString)  
  97.    {  
  98.       out.println(  
  99.          "\n===================================================================");  
  100.       out.println("== " + headerString);  
  101.       out.println(  
  102.          "===================================================================");  
  103.    }  
  104.   
  105.    /** 
  106.     * Main executable function for demonstrating Arrays.toString(Object[]) and 
  107.     * Arrays.deepToString(Object[]) methods. 
  108.     */  
  109.    public static void main(final String[] arguments)  
  110.    {  
  111.       demonstrateDirectArrayString();  
  112.       demonstrateArraysToString();  
  113.       demonstrateArraysDeepToString();  
  114.    }  
  115. }  

The above code exercises the three mentioned approaches for getting a String out of an array on the three different types of arrays: single dimension, multi dimension, and null array. The output from running this code demonstrates the utility of the different approaches. That output is shown next.

===================================================================
== Object[].toString() [implicit or explicit]
===================================================================
Single Dimension toString(): [Ljava.lang.String;@3e25a5
Double Dimension toString(): [[Ljava.lang.Object;@19821f
Null Array toString(): null

===================================================================
== Arrays.toString(Object[])
===================================================================
Single Dimension Arrays.toString: [Aaron, Bianca, Charles, Denise, Elmer]
Double Dimension Arrays.toString: [[Ljava.lang.Object;@addbf1, [Ljava.lang.Object;@42e816, [Ljava.lang.Object;@9304b1, [Ljava.lang.Object;@190d11, [Ljava.lang.Object;@a90653]
Null Array Arrays.toString: null

===================================================================
== Arrays.deepToString(Object[])
===================================================================
Single Dimension Arrays.deepToString: [Aaron, Bianca, Charles, Denise, Elmer]
Double Dimension Arrays.deepToString: [[Aaron, 10], [Bianca, 25], [Charles, 32], [Denise, 29], [Elmer, 67]]
Null Array Arrays.deepToString: null

The code above and its corresponding output lead to several observations:
  1. Simple Object.toString() on arrays is seldom what we want as it only prints the String representation of the array itself and not of its contents.
  2. Arrays.toString(Object[]) will print a String representation for multi-dimensional arrays, but this representation suffers the same drawbacks as Object.toString() after the first dimension. The first dimension (and only dimension for a single dimension array) gets put into an expected String, but deeper dimensions have the same Object.toString() treatment.
  3. Arrays.deepToString(Object[]), while intended for multi-dimensional arrays, produces the expected results for both single and multi-dimensional arrays.
  4. Both Arrays.toString(Object[]) and Arrays.deepToString(Object[]) handle null array gracefully, simply returning a String "null".
I tend to use Java Collections far more than I use Java arrays. However, when I do need to work with arrays, it is nice to have the many useful features of the java.util.Arrays class. As this post has demonstrated, Arrays.toString(Object[]) and Arrays.deepToString(Object[]) are particularly valuable in obtaining a useful String representation of an array's contents. The java.util.Arrays class provides similar "deep" methods for performing equals and hashCode functionality on multi-dimensional arrays: Arrays.deepEquals and Arrays.deepHashCode.

4 comments:

Mohamed Sanaulla said...

I follow your blog posts- and almost all the times- there's something new which I learn from your posts. And your posts are descriptive with code examples as well.
But there's one thing- the text area is very less due to which the code gets split into multiple lines. So you can try using a different theme where u have lot of text space. Or you can even try wordpress ( I find it really good).

@DustinMarx said...

Mohamed,

Thanks for the feedback. Although I do really like this template and color schemes, I agree with you that the presentation of code listings leaves something to be desired. Because I tend to use a lot of code examples, this can be a problem. I'll look into some ways to improve it. Thanks again for taking the time to provide the feedback.

Dustin

Unknown said...

You can keep the template and color scheme (incidentally, I use the same one for my blog). There is a "Template Designer" tab when you go to the Design page. In the Template Designer, there is a "Layout" button that lets you choose the overall width as well as the width of the right column.

@DustinMarx said...

Ingo,

Thanks for the tip. I was thinking about changing the HTML/CSS directly, but I like your idea better. I also checked out use of this template on your blog.

Dustin