Java 使用CollectionUtils转换列表会引发ArrayStoreException

Java 使用CollectionUtils转换列表会引发ArrayStoreException,java,collections,apache-commons,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(StringUti

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)
为什么会这样?

当试图将不正确类型的对象存储到数组中时,会发生这种情况

代码在做什么?

在给出的示例代码中,该方法采用a并对元素执行就地转换,这意味着将
对象
从原始
集合
(例如a)中取出并放回相同的
集合

的代码获取一个
字符串
,并将其转换为一个
整数
——这是这里的核心问题——应用转换时,对象的类型正在发生变化

会出什么问题?

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

我怀疑由创建的
列表
字符串[]
支持,因为这可能是
阵列存储异常
的来源。运行调试器确认了这一点,因为它由
字符串[5]
支持。(使用Eclipse,在Windows上的JRE 6上运行。)

这个例子说明了什么?

这是一个主要的例子,说明缺乏泛型如何允许编写类型不安全的代码,从而在运行时出现问题。如果代码是用泛型编写的(Apache Commons Collection支持它),那么这些类型的问题将在编译时被捕获

底线——不能转换
列表中的类型元素
——如果
列表
包含
字符串
s,则只应返回
字符串

可以做什么?

作为替代方案,它有一个方法,该方法接受给定的
集合
,并返回一个由


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

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

public static <T> List<T> asList(T... a) {
    return new ArrayList<T>(a);
}
公共静态列表asList(T…a){
返回新的ArrayList(a);
}
调用
StringUtils.split
将创建一个
String[]
,并将其传递给
Arrays.asList
方法。这将限制可以插入到新列表实例中的元素类型仅限于
String
对象

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

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

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


  • 根据您试图解决的场景,您应该使用第二种类型的转换并调用
    collect()
    变体之一。

    可以将其更改为使用
    Arrays.asList(xxx)
    ,或
    Arrays.asList(新对象[]{xxx})
    。最好在整个过程中使用泛型,这会使就地转换变得可疑。最好放弃Apache commons集合。