Почему возникает UnsupportedOperationException при попытке удалить элемент из списка?
Я столкнулся с проблемой в следующем коде на Java:
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)
Проблема, похоже, связана с тем, что метод Arrays.asList()
возвращает фиксированный по размеру список, поэтому я не могу удалять элементы из него. Как правильно изменить этот код, чтобы он работал без ошибок? Я использую Java 15.
5 ответ(ов)
Это мне уже несколько раз доставляло проблемы. Arrays.asList
создает неизменяемый список. В документации написано: возвращает список фиксированного размера, основанный на указанном массиве.
Чтобы создать новый список с таким же содержимым, можно сделать так:
newList.addAll(Arrays.asList(newArray));
Это создаст немного лишнего мусора, но вы сможете изменять его.
Список, возвращаемый методом Arrays.asList()
, может быть неизменяемым. Попробуйте использовать следующий код:
List<String> list = new ArrayList<>(Arrays.asList(split));
Таким образом, вы создадите новый изменяемый список на основе массива.
Да, я думаю, что замена:
List<String> list = Arrays.asList(split);
на
List<String> list = new ArrayList<String>(Arrays.asList(split));
действительно решит проблему.
Когда вы используете Arrays.asList()
, вы получаете фиксированный размер списка, который не позволяет добавлять или удалять элементы. Создавая новый ArrayList
, вы получаете изменяемый список, с которым можно работать более гибко. Таким образом, ваш код будет работать правильно, если вам нужно будет модифицировать полученный список.
Проблема заключается в том, что вы создаете список с помощью метода Arrays.asList()
, который возвращает список фиксированного размера. Это означает, что:
Поскольку возвращаемый список имеет фиксированный размер, мы не можем добавлять или удалять элементы.
Посмотрите на следующий фрагмент кода, который я использую:
List<String> words = Arrays.asList("pen", "pencil", "sky", "blue", "sky", "dog");
for (String word : words) {
if ("sky".equals(word)) {
words.remove(word);
}
}
Эта итерация вызовет исключение, поскольку это итерация по списку, созданному с помощью метода
asList()
, и добавление/удаление элементов невозможно — это фиксированный массив.
Вместо этого, вот как будет выглядеть рабочий вариант:
List<String> words1 = new ArrayList<String>(Arrays.asList("pen", "pencil", "sky", "blue", "sky", "dog"));
for (String word : words1) {
if ("sky".equals(word)) {
words1.remove(word);
}
}
Это будет работать корректно, так как мы создаем новый
ArrayList
, и можем выполнять модификации во время итерации.
Обратите внимание, что в обоих случаях важно использовать переменную words1
в цикле для итерации, чтобы избежать путаницы.
Просто прочитайте JavaDoc для метода asList
:
Возвращает {@code List} объектов из указанного массива. Размер {@code List} не может быть изменен, т.е. добавление и удаление элементов не поддерживаются, но элементы могут быть установлены. Установка элемента изменяет исходный массив.
Это из Java 6, но кажется, что для Android Java это так же.
ДОПОЛНЕНИЕ
Тип полученного списка - Arrays.ArrayList
, который является приватным классом внутри Arrays.class
. Практически, это всего лишь представление списка для массива, который вы передали в Arrays.asList
. Как следствие: если вы измените массив, список изменится тоже. И поскольку массив не может быть изменен по размеру, операции удаления и добавления должны быть неподдерживаемыми.
Преобразование списка в массив в Java
Как проверить, что в JUnit-тестах выбрасывается определенное исключение?
Инициализация ArrayList в одну строчку
Преобразование 'ArrayList<String>' в 'String[]' в Java
Как преобразовать Map в List в Java?