Monday, October 5, 2009

Groovy JDK (GDK): Object[] and T[]

The Groovy JDK (GDK) provides many convenience methods that can be invoked on arrays. The GDK includes specific support for many array types such as Byte[], byte[], boolean[], double[], float[], int[], and long[]. The GDK also supports String[], T[], and Object[]. I'll focus on the last two (Object[] and T[]) in this blog posting.

In this post, I'll have the some of the Groovy code reference a Java class called Person.java and the code listing for that class is shown next.

Person.java

package dustin.examples;

/**
* Simple class to be used in Groovy Object[] examples.
*/
public class Person
{
private final String lastName;
private final String firstName;

public Person(final String newLastName, final String newFirstName)
{
this.lastName = newLastName;
this.firstName = newFirstName;
}

@Override
public boolean equals(Object obj)
{
if (obj == null)
{
return false;
}
if (getClass() != obj.getClass())
{
return false;
}
final Person other = (Person) obj;
if (this == null ? other != null : !this.lastName.equals(other.lastName))
{
return false;
}
if (this == null ? other != null : !this.firstName.equals(other.firstName))
{
return false;
}
return true;
}

@Override
public int hashCode()
{
int hash = 3;
hash = 97 * hash + (this.lastName != null ? this.lastName.hashCode() : 0);
hash = 97 * hash + (this.firstName != null ? this.firstName.hashCode() : 0);
return hash;
}

@Override
public String toString()
{
return this.firstName + " " + this.lastName;
}
}


In Java, there isn't much one can do directly with an array of the above objects. The next code sample demonstrates some of the limited functionality available with direct use of an array:

JavaArrays.java

package dustin.examples;

import static java.lang.System.out;

/**
* Simple example class that demonstrates functionality on Java arrays.
*/
public class JavaArrays
{
public static void main(final String[] arguments)
{
final Person[] objectArray =
{ new Person("Flintstone", "Fred"), new Person("Rubble", "Barney") };
out.println("Length of array is " + objectArray.length);
out.println("Array toString is " + objectArray.toString());
}
}


When the above code is executed, the output looks like that shown in the next screen snapshot:



The output of a toString call on an array is not very helpful. As I discussed in the blog post Java Arrays: Copying, String Representation, and Collections, the java.util.Arrays class provides some useful methods for dealing with arrays. In Groovy, many of these same convenient methods are available directly on the arrays themselves thanks to Object[] and T[]. In the remainder of this blog post, I will look at some of these direct Groovy array method support in detail.

In this first snippet from my Groovy script groovyObjectArray.groovy, the Object[].asType(Class)
method is demonstrated. This method allows an array of Objects to be treated as a Set of Objects or a List of Objects. The version that provides a SortedSet is commented out because the objects in the collection need to be Comparable for a SortedSet and our custom Person class is not Comparable.

groovyObjectArray.groovy (part 1)

import dustin.examples.Person

Object[] objectArray = [new Person("Flintstone", "Fred"), new Person("Rubble", "Barney")]
println "objectArray's class type: ${objectArray.getClass().name}"
objectSet = objectArray.asType(java.util.Set)
println "objectSet's class type: ${objectSet.getClass().name}"
objectList = objectArray.asType(java.util.List)
println "objectList's class type: ${objectList.getClass().name}"
// Running Object[].asType(java.util.SortedSet) requires elements in array of
// objects to implement the Comparable interface because that is a requirement
// of java.util.SortedSet. A ClassCastException is encountered if the objects
// do not implement Comparable: "cannot be cast to java.util.Comparable"
//objectSortedSet = objectArray.asType(java.lang.SortedSet)
//println "objectSortedSet's class type: ${objectSortedSet.getClass().name}"


The output for these first few lines of Groovy code is shown next.



Object[] provides several more useful and convenient methods for accessing array elements. Some of these (Object[].size(), Object[].toArrayString(), Object[].toString(), Object[].join(), and Object[].count()) are shown in the next code listing, the second part of the script groovyObjectArray.groovy.

groovyObjectArray.groovy (part 2)

println "objectArray #items (.length property): ${objectArray.length}"
println "objectArray #items (size() method): ${objectArray.size()}"
println "objectArray toArrayString: ${objectArray.toArrayString()}"
println "objectArray toString: ${objectArray.toString()}"
println "objectArray join with <--->: ${objectArray.join('<--->')}"

// The Object[].count method requires Groovy 1.6.4.
personToMatch = new Person("Flintstone", "Fred")
println "objectArray #contained items: ${objectArray.count(personToMatch)}"


The output from the above snippet of the script is shown next.



As the above code listing and its corresponding output indicate, the Object[].toString() and Object[].toArrayString() methods provide nice String representations of the array contents. The Object[].size() method is a method-based approach to get the size or length of the array. The Object[].join(String) method joins the String representations of the elements of the array to each other with the provided String-based separator joining them. The Object[].count(Object) method has only been available since Groovy 1.6.4 and provides the number of instances of the provided Object within that array.

The third and final part of the groovyObjectArray.groovy script demonstrates the useful methods on T[] that provide minimum and maximum values of the elements of the array. The elements need to be comparable for these to work and I use Strings, integers, and doubles respectively.

groovyObjectArray.groovy (part 3)

// Use methods on T[]
Object[] stringArray = ["One", "Two", "Three", "Four", "Five"]
Object[] integerArray = [1, 2, 3, 4 ,5]
Object[] doubleArray = [1.0, 2.5, 5.0, 7.5, 10.0]
println "stringArray.max(): ${stringArray.max()}"
println "stringArray.min(): ${stringArray.min()}"
println "integerArray.max(): ${integerArray.max()}"
println "integerArray.mix(): ${integerArray.min()}"
println "doubleArray.max(): ${doubleArray.max()}"
println "doubleArray.min(): ${doubleArray.min()}"


The output from the above is shown in the next screen snapshot.




This posting has demonstrated the useful convenience methods provided for array access and manipulation in Groovy GDK with Object[] and T[].

No comments: