Почему я получаю 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

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

В Arrays.asList, возвращающем список фиксированного размера

Из API:

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

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

Fix

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

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

Вкл split с использованием регулярного выражения

Из API:

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

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

Fix:

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

Я думаю, что замена:

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

с

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

устраняет проблему.

Ответ 5

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

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

Ответ 6

Просто прочитайте JavaDoc для метода asList:

Возвращает список {@code List} объектов в указанном массиве. Размер {@code List} не может быть изменен, то есть добавление и удаление неподдерживаемые, но элементы могут быть задавать. Установка элемента изменяет базовый массив.

Это из Java 6, но похоже, что он одинаковый для java версии android.

ИЗМЕНИТЬ

Тип результирующего списка Arrays.ArrayList, который является частным классом внутри Arrays.class. Фактически, это не что иное, как представление List на массив, который вы передали с помощью Arrays.asList. В результате: если вы измените массив, список тоже изменится. И поскольку массив не изменяется по размеру, удаление и добавление операции должно быть неподдерживаемым.

Ответ 7

Arrays.asList() возвращает список, который не позволяет выполнять операции, влияющие на его размер (обратите внимание, что это не то же самое, что "немодифицируемое" ).

Вы можете сделать new ArrayList<String>(Arrays.asList(split));, чтобы создать реальную копию, но, видя то, что вы пытаетесь сделать, вот дополнительное предложение (у вас есть алгоритм O(n^2), который находится ниже).

Вы хотите удалить list.size() - count (позволяет вызывать это k) случайные элементы из списка. Просто выберите столько случайных элементов и поменяйте их до конца k позиций списка, затем удалите весь диапазон (например, используя subList() и clear() на этом). Это превратило бы его в скудный и средний O(n) алгоритм (O(k) точнее).

Обновление. Как отмечено ниже, этот алгоритм имеет смысл только в том случае, если элементы неупорядочены, например. если Список представляет собой Сумку. Если, с другой стороны, Список имеет значимый порядок, этот алгоритм не сохранит его (вместо этого алгоритм полигенных смазок).

Обновление 2. Таким образом, в ретроспективе лучший (линейный, поддерживающий порядок, но с O (n) случайным числом) алгоритм будет примерно таким:

LinkedList<String> elements = ...; //to avoid the slow ArrayList.remove()
int k = elements.size() - count; //elements to select/delete
int remaining = elements.size(); //elements remaining to be iterated
for (Iterator i = elements.iterator(); k > 0 && i.hasNext(); remaining--) {
  i.next();
  if (random.nextInt(remaining) < k) {
     //or (random.nextDouble() < (double)k/remaining)
     i.remove();
     k--;
  }
}

Ответ 8

У меня есть другое решение для этой проблемы:

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

работает над newList;)

Ответ 9

Это UnsupportedOperationException возникает, когда вы пытаетесь выполнить некоторую операцию в коллекции, где ее не разрешено и в вашем случае. Когда вы вызываете Arrays.asList, он не возвращает java.util.ArrayList. Он возвращает java.util.Arrays$ArrayList, который является неизменным. Вы не можете добавить к нему, и вы не можете удалить его.

Ответ 10

Да, на Arrays.asList, возвращая список фиксированного размера.

Кроме использования связанного списка, просто используйте список методов addAll.

Пример:

String idList = "123,222,333,444";

List<String> parentRecepeIdList = new ArrayList<String>();

parentRecepeIdList.addAll(Arrays.asList(idList.split(","))); 

parentRecepeIdList.add("555");

Ответ 11

Вы не можете удалить и не добавить в список массивов с фиксированным размером.

Но вы можете создать свой подсписок из этого списка.

list = list.subList(0, list.size() - (list.size() - count));

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 = list.subList(0, list.size() - (list.size() - count));
   }
   return StringUtils.join(list, ", ");
}

* Другой способ -

ArrayList<String> al = new ArrayList<String>(Arrays.asList(template));

это создаст ArrayList, который не является фиксированным размером, например Arrays.asList

Ответ 12

Ниже приведен фрагмент кода из массивов

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

    /**
     * @serial include
     */
    private static class ArrayList<E> extends AbstractList<E>
        implements RandomAccess, java.io.Serializable
    {
        private static final long serialVersionUID = -2764017481108945198L;
        private final E[] a;

так что происходит, когда вызывается метод asList, он возвращает список своей собственной частной статической версии класса, которая не отменяет добавление funcion из AbstractList для хранения элемента в массиве. Поэтому по умолчанию метод add в абстрактном списке вызывает исключение.

Таким образом, это не обычный список массивов.

Ответ 13

замещать

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

в

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

или же

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

или же

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

или (лучше для удаления элементов)

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

Ответ 14

Arraylist narraylist = Arrays.asList(); // Возвращает неизменяемый arraylist Чтобы сделать его изменяемым, было бы следующее: Arraylist narraylist = new ArrayList (Arrays.asList());

Ответ 15

Arrays.asList() использует массив фиксированного размера внутри.
Вы не можете динамически добавлять или удалять из этого Arrays.asList()

Использовать этот

Arraylist<String> narraylist=new ArrayList(Arrays.asList());

В narraylist вы можете легко добавлять или удалять элементы.

Ответ 16

Создание нового списка и заполнение допустимых значений в новом списке работало для меня.

Ошибка при создании кода -

List<String> list = new ArrayList<>();
   for (String s: list) {
     if(s is null or blank) {
        list.remove(s);
     }
   }
desiredObject.setValue(list);

После исправления -

 List<String> list = new ArrayList<>();
 List<String> newList= new ArrayList<>();
 for (String s: list) {
   if(s is null or blank) {
      continue;
   }
   newList.add(s);
 }
 desiredObject.setValue(newList);