Вопрос-ответ

Why do I get an UnsupportedOperationException when trying to remove an element from a List?

Почему я получаю исключение UnsupportedOperationException при попытке удалить элемент из списка?

У меня есть этот код:

public static String SelectRandomFromTemplate(String template,int count) {
String[] split = template.split("|");
List<String> list=Arrays.asList(split);
Random r = new Random();
while( list.size() > count ) {
list.remove(r.nextInt(list.size()));
}
return StringUtils.join(list, ", ");
}

Я получаю это:

06-03 15:05:29.614: ERROR/AndroidRuntime(7737): java.lang.UnsupportedOperationException
06-03 15:05:29.614: ERROR/AndroidRuntime(7737): at java.util.AbstractList.remove(AbstractList.java:645)

Как это было бы правильно? Java.15

Переведено автоматически
Ответ 1

Довольно много проблем с вашим кодом:

On Arrays.asList возвращает список фиксированного размера

Из API:


Arrays.asList: Возвращает список фиксированного размера, поддерживаемый указанным массивом.


Вы не можете add к нему; вы не можете remove из него. Вы не можете структурно изменить List.

Исправлено

Создайте LinkedList, который поддерживает более быстрый remove.

List<String> list = new LinkedList<String>(Arrays.asList(split));

О split принятии регулярного выражения

Из API:


String.split(String regex): Разбивает эту строку на совпадения с данным регулярным выражением.


| это метасимвол регулярного выражения; если вы хотите разделить на литерал |, вы должны экранировать его в \|, который в качестве строкового литерала Java является "\\|".

Исправлено:

template.split("\\|")

О лучшем алгоритме

Вместо вызова remove по одному со случайными индексами, лучше сгенерировать достаточное количество случайных чисел в диапазоне, а затем обойти List один раз с помощью listIterator(), вызывая remove() по соответствующим индексам. В stackoverflow есть вопросы о том, как генерировать случайные, но разные числа в заданном диапазоне.

При этом ваш алгоритм будет O(N).

Ответ 2

Это меня раздражало много раз. Arrays.asList создает неизменяемый список. Из Javadoc: возвращает список фиксированного размера, поддерживаемый указанным массивом.

Создайте новый список с тем же содержимым:

newList.addAll(Arrays.asList(newArray));

Это создаст немного дополнительного мусора, но вы сможете изменить его.

Ответ 3

Вероятно, потому, что вы работаете с неизменяемой оболочкой.

Измените эту строку:

List<String> list = Arrays.asList(split);

к этой строке:

List<String> list = new LinkedList<>(Arrays.asList(split));
Ответ 4

Список, возвращаемый Arrays.asList(), может быть неизменяемым. Не могли бы вы попробовать

List<String> list = new ArrayList<>(Arrays.asList(split));
java exception list arraylist