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