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)
为什么?
答案 0 :(得分:5)
当尝试将不正确类型的对象存储到数组中时,会出现ArrayStoreException
。
代码在做什么?
在给出的示例代码中,CollectionUtil.transform
方法采用Collection
并执行元素的就地转换,这意味着Object
s取自原始{ {1}}(例如List
)并放回同一Collection
。
Transformer
的代码需要Collection
并将其转换为String
- 这是核心问题 - 对象的类型在转换时会发生变化已应用。
可能出现什么问题?
如前所述,Integer
将使用给定的CollectionUtil.transform
并对Transformer
中的每个元素执行转换,并将其存储回原始Collection
,即Collection
。
我怀疑strList
创建的List
由String[]
支持,因为这可能是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
类支持两种不同类型的转换:
就地转换 - 在这种情况下,输入集合实例会使用转换后的值进行更新。所有transform()
变体都属于此类别。当使用由数组支持的Collection类型(例如ArrayList)时,只有当转换后的值与后备数组类型类型兼容时,转换才能成功。 这解释了您所看到的例外情况。
不合适的转换 - 在这种情况下,输入集合永远不会更新。而是将转换后的值收集在单独的集合实例中。所有collect()
变体都属于第二类。 collect()方法的重载版本接受输出集合作为参数,或者如果未指定单独的集合,则创建新的列表实例以收集转换后的值。
根据您尝试解决的方案,您应该使用第二种类型的转换并调用其中一个collect()
变体。