Преобразование списка с использованием CollectionUtils создает исключение ArrayStoreException - PullRequest
3 голосов
/ 16 января 2010

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 ]

5 голосов
/ 16 января 2010

ArrayStoreException возникает, когда делается попытка сохранить объект неправильного типа в массиве.

Что делает код?

В приведенном примере кода метод CollectionUtil.transform принимает Collection и выполняет преобразование элементов на месте, что означает, что Object s вынутый из оригинала Collection (такой как List) и помещенный обратно в тот же Collection.

Код для Transformer принимает String и преобразует его в Integer - это основная проблема здесь - тип объекта изменяется при преобразовании применяется .

Что может быть не так?

Как упоминалось ранее, CollectionUtil.transform будет использовать данный Transformer и выполнит преобразование для каждого элемента в Collection и сохранит его обратно в исходный Collection, который является strList.

Я подозревал, что List, созданный Arrays.asList, поддерживается String[], поскольку это, вероятно, будет источником ArrayStoreException. Запуск отладчика подтвердил это, поскольку он был поддержан String[5]. (Используя Eclipse, работающий на JRE 6 в Windows.)

Что иллюстрирует этот пример?

Это яркий пример того, как отсутствие обобщений позволяет писать код, который не является безопасным для типов, и, следовательно, возникает проблема во время выполнения. Если код был написан с использованием дженериков (и Apache Commons Collection его поддерживал), эти типы проблем будут обнаружены во время компиляции.

Нижняя строка - нельзя преобразовать элементы типа в List - если List содержит String с, Transformer.transform должен возвращать только String.

Что можно сделать?

В качестве альтернативы Google Collections имеет метод Collections2.transform, который принимает заданный Collection и возвращает Collection, преобразованный в Function .

Этот метод поддерживает дженерики, поэтому он безопасен от типов, и тот факт, что он возвращает новый Collection, означает, что типы могут изменяться в процессе преобразования.

1 голос
/ 19 апреля 2014

Метод Arrays.asList использует тот же предоставленный массив, что и вспомогательный массив для нового экземпляра списка. Код API выглядит следующим образом:

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

Вызов StringUtils.split создает String[], который передается методу Arrays.asList. Это ограничит тип элементов, которые вы можете вставить в новый экземпляр списка, только String объектами.

CollectionUtils класс поддерживает 2 различных типа преобразований:

  1. Преобразование на месте - В этом случае экземпляр входной коллекции обновляется с преобразованными значениями. Все варианты transform() попадают в эту категорию. При использовании типов Collection, которые поддерживаются массивами (например, ArrayList), преобразование может быть успешным, только когда преобразованные значения совместимы по типу с типом резервного массива. Это объясняет исключение, которое вы видите.

  2. Преобразование вне места - В этом случае коллекция входных данных никогда не обновляется. Вместо этого преобразованные значения собираются в отдельном экземпляре коллекции. Все варианты collect() попадают в эту вторую категорию. Перегруженные версии метода collect () принимают выходную коллекцию в качестве аргумента или, если отдельная коллекция не указана, создает новый экземпляр списка для сбора преобразованных значений.

Исходя из сценария, к которому вы пытаетесь обратиться, вы должны перейти ко 2-му типу преобразования и вызвать один из collect() вариантов.

...