使用CollectionUtils转换List会抛出ArrayStoreException

时间:2010-01-16 02:39:48

标签: java collections apache-commons

Java代码:

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);

此代码将抛出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)

为什么?

2 个答案:

答案 0 :(得分:5)

当尝试将不正确类型的对象存储到数组中时,会出现ArrayStoreException

代码在做什么?

在给出的示例代码中,CollectionUtil.transform方法采用Collection并执行元素的就地转换,这意味着Object s取自原始{ {1}}(例如List)并放回同一Collection

Transformer的代码需要Collection并将其转换为String - 这是核心问题 - 对象的类型在转换时会发生变化已应用

可能出现什么问题?

如前所述,Integer将使用给定的CollectionUtil.transform并对Transformer中的每个元素执行转换,并将其存储回原始Collection,即Collection

我怀疑strList创建的ListString[]支持,因为这可能是ArrayStoreException的来源。运行调试器确认,因为它由String[5]支持。 (使用Eclipse,在Windows上的JRE 6上运行。)

这个例子说明了什么?

这是缺少泛型如何允许编写非类型安全的代码的一个主要示例,因此,在运行时出现问题。如果代码是用泛型编写的(并且Apache Commons Collection支持它),那么这些类型的问题将在编译时被捕获。

底线 - 无法转换List中的类型元素 - 如果List包含String s,则Arrays.asList只应返回{{1} }}

可以做些什么?

作为替代方案,Transformer.transform有一个Google Collections方法,该方法需要String,并返回由Collections2.transform转换的Collection

此方法支持泛型,因此它是类型安全的,并且它返回新的Collection这意味着类型可以通过转换进行更改。

答案 1 :(得分:1)

Arrays.asList方法使用相同的提供数组作为新列表实例的支持数组。 API代码如下所示:

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

StringUtils.split的调用会创建String[],并传递给Arrays.asList方法。这会将您可以插入新列表实例的元素类型限制为仅String个对象。

CollectionUtils类支持两种不同类型的转换:

  1. 就地转换 - 在这种情况下,输入集合实例会使用转换后的值进行更新。所有transform()变体都属于此类别。当使用由数组支持的Collection类型(例如ArrayList)时,只有当转换后的值与后备数组类型类型兼容时,转换才能成功。 这解释了您所看到的例外情况。

  2. 不合适的转换 - 在这种情况下,输入集合永远不会更新。而是将转换后的值收集在单独的集合实例中。所有collect()变体都属于第二类。 collect()方法的重载版本接受输出集合作为参数,或者如果未指定单独的集合,则创建新的列表实例以收集转换后的值。

  3. 根据您尝试解决的方案,您应该使用第二种类型的转换并调用其中一个collect()变体。