开发者

Transforming List using CollectionUtils throws ArrayStoreException

开发者 https://www.devze.com 2022-12-16 19:11 出处:网络
Java code: Transformer TRANSFORM_TO_INTEGER = new Transformer(开发者_如何学编程) { public Object transform(Object input) {

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?


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.


The Arrays.asList method uses the same supplied array as the backing array for the new list instance. The API code looks like the following:

public static <T> List<T> asList(T... a) {
    return new ArrayList<T>(a);
}

The call to StringUtils.split creates a String[] which is passed to the Arrays.asList method. This would restrict the type of elements that you can insert into the new list instance to only String objects.

CollectionUtils class supports 2 different types of transformations:

  1. In place transformation - In this case the input collection instance gets updated with the transformed values. All the transform() variants fall in this category. When using Collection types which are backed by arrays (e.g. ArrayList) the transformation can be successful only when the transformed values are type compatible with the backing array type. This explains the exception that you are seeing.

  2. Out of place transformation - In this case the input collection is never updated. Instead the transformed values are collected in a separate collection instance. All the collect() variants fall in this second category. The overloaded versions of collect() method either accepts the output collection as an argument or if no separate collection is specified creates a new list instance to collect the transformed values.

Based on the scenario that you are trying to address you should go with the 2nd type of transformation and call one of the collect() variants.

0

精彩评论

暂无评论...
验证码 换一张
取 消