简体   繁体   English

使用CollectionUtils转换List会抛出ArrayStoreException

[英]Transforming List using CollectionUtils throws ArrayStoreException

Java code: 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);

This code would throw ArrayStoreException: 此代码将抛出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. 当尝试将不正确类型的对象存储到数组中时,会发生ArrayStoreException

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 Object s are taken out of the original Collection (such as a List ) and placed back into the same Collection . 在给出的示例代码中, CollectionUtil.transform方法接受Collection并执行元素的就地转换,这意味着Object从原始Collection (例如List )中取出并放回到同一个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 . Transformer的代码采用String并将其转换为Integer - 这是核心问题 - 应用转换时对象的类型正在发生变化

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 . 如前所述, CollectionUtil.transform将使用给定的Transformer并对Collection每个元素执行转换,并将其存储回原始Collection ,即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 . 我怀疑该List由创建Arrays.asList正在被支持String[]因为这将是可能的是源ArrayStoreException Running the debugger confirmed that, as it was backed by a String[5] . 运行调试器确认,因为它由String[5] (Using Eclipse, running on JRE 6 on Windows.) (使用Eclipse,在Windows上运行JRE 6。)

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. 如果代码是用泛型编写的(并且Apache Commons Collection支持它),那么这些类型的问题将在编译时捕获。

The bottom line -- one cannot transform type elements in a List -- if the List contains String s, the Transformer.transform should only return a String . 底线 - 一个不能转换List类型元素 - 如果List包含String ,则Transformer.transform只应返回一个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 . 作为替代方案, Google Collections有一个Collections2.transform方法,它接受一个给定的Collection并返回一个由Function转换的Collection

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. 此方法支持泛型,因此它是类型安全的,并且它返回新Collection的事实意味着类型可以通过转换进行更改。

The Arrays.asList method uses the same supplied array as the backing array for the new list instance. Arrays.asList方法使用相同的提供数组作为新列表实例的后备数组。 The API code looks like the following: API代码如下所示:

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. StringUtils.split的调用创建了一个String[] ,它传递给Arrays.asList方法。 This would restrict the type of elements that you can insert into the new list instance to only String objects. 这会将您可以插入新列表实例的元素类型限制为仅限String对象。

CollectionUtils class supports 2 different types of transformations: CollectionUtils类支持2种不同类型的转换:

  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. 所有transform()变体都属于这一类。 When using Collection types which are backed by arrays (eg ArrayList) the transformation can be successful only when the transformed values are type compatible with the backing array type. 当使用由数组支持的Collection类型(例如ArrayList)时,只有当转换后的值与后备数组类型兼容时,转换才能成功。 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. 所有collect()变体都属于第二类。 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. collect()方法的重载版本接受输出集合作为参数,或者如果未指定单独的集合,则创建新的列表实例以收集转换的值。

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. 根据您尝试解决的方案,您应该使用第二种类型的转换并调用其中一个collect()变体。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM