views:

332

answers:

1

Java code:

Transformer TRANSFORM_TO_INTEGER = new Transformer() {
    public Object transform(Object input) {
        Integer i = new Integer((String) input);
        return i;
    }
};

String begin = "1,2,3,4,5";
List strList = Arrays.asList(StringUtils.split(begin, ","));
CollectionUtils.transform(strList, TRANSFORM_TO_INTEGER);

This code would throw ArrayStoreException:

java.lang.ArrayStoreException
at java.util.Arrays$ArrayList.set(Arrays.java:2360)
at java.util.AbstractList$ListItr.set(AbstractList.java:488)
at org.apache.commons.collections.CollectionUtils.transform(CollectionUtils.java:434)

Why is that?

+3  A: 

The ArrayStoreException occurs when an attempt is made to store an object of an incorrect type is placed into an array.

What is the code doing?

In the example code given, the CollectionUtil.transform method takes a Collection and performs an in-place transform of the elements, which means that Objects are taken out of the original Collection (such as a List) and placed back into the same Collection.

The code for the Transformer takes a String and transforms it into a Integer -- this is core issue here -- the type of object is changing when the transform is applied.

What could be going wrong?

As previously mentioned, CollectionUtil.transform will use the given Transformer and perform the transformation on each element in the Collection and store it back to the original Collection, which is the strList.

I suspected that the List created by Arrays.asList is being backed by a String[], as that would be the likely be the source of the ArrayStoreException. Running the debugger confirmed that, as it was backed by a String[5]. (Using Eclipse, running on JRE 6 on Windows.)

What does the this example illustrate?

This is a prime example of how the lack of generics allows code that is not typesafe to be written, and consequently, a problem arises at runtime. If the code had been written with generics (and Apache Commons Collection supported it) these types of problems would be caught at compile time.

The bottom line -- one cannot transform type elements in a List -- if the List contains Strings, the Transformer.transform should only return a String.

What can be done?

As an alternative, Google Collections has a Collections2.transform method, which takes a given Collection and returns a Collection transformed by a Function.

This method supports generics, so it is typesafe, and the fact it returns a new Collection means that the types can change through the transformation.

coobird
It could be changed to use `Arrays.<Object>asList(xxx)`, or `Arrays.asList(new Object[] { xxx })`. Better off using generics throughout, which would make the in-place transform suspect. Probably better off abandoning Apache commons collections.
Tom Hawtin - tackline
what if I'm using JDK1.4
jackysee