remove () в списке, созданном Arrays.asList (), выдает исключение UnsupportedOperationException

91

У меня есть коллекция c1<MyClass>и массив a<MyClass>. Я пытаюсь преобразовать массив в коллекцию c2и делаю это c1.removeAll(c2), но это бросает UnsupportedOperationException. Я обнаружил , что asList()из Массивы возвращает класс Arrays.ArrayListкласса и этот класса наследует removeAll()от AbstractList()которого реализации бросков UnsupportedOperationException.

    Myclass la[] = getMyClass();
    Collection c = Arrays.asList(la);
    c.removeAll(thisAllreadyExistingMyClass);

Есть ли способ удалить элементы? пожалуйста помоги

javalearner
источник
Связанный вопрос: stackoverflow.com/questions/2965747/…
Ram

Ответы:

173

Arrays.asListвозвращает Listоболочку вокруг массива. Эта оболочка имеет фиксированный размер и напрямую поддерживается массивом, поэтому вызовы to setбудут изменять массив, а любой другой метод, изменяющий список, будет генерировать файл UnsupportedOperationException.

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

Collection c = new ArrayList(Arrays.asList(la));
Этьен де Мартель
источник
1
Я смотрел исходный код java.util.Arrays asList()метода, и, похоже, он возвращает ArrayList. Однако когда я делаю это System.out.println(list.getClass());, я получаю class java.util.Arrays$ArrayList. Таким образом, он использует внутренний ArrayListкласс, у которого нет метода addили remove. Мне просто интересно, какой смысл иметь внутренний ArrayListкласс вместо того, чтобы использовать его, java.util.ArrayListи почему бы не иметь метод add()and remove()?
Абдул
Исправление к моему выше комментарию: она есть addи removeметод
Абдул
1
@Abdul Потому что фиксированного размера не существует java.util.ArrayList. Вам нужна реализация, Listкоторая генерирует исключение, если вы делаете с ним что-то незаконное (например, добавляете или удаляете), и ArrayListне удовлетворяет этому требованию.
Этьен де Мартель,
@Abdul Arrays.asListпросто создает оболочку List. Но это по-прежнему a java.util.List, поэтому у него должны быть эти методы. Но их нельзя применить, потому что это приведет к созданию нового массива с другим размером. Что невозможно сделать, потому что изменения, которые вы все еще можете сделать, можно выполнить как через возвращенный список, так и через исходный массив. Это было бы невозможно, если бы возвращенный список мог измениться так, чтобы он в основном отбрасывал исходную ссылку на массив.
Адам Хошек
13

Ага, Arrays.asList(..)это коллекция, которую нельзя расширить или сжать (потому что она поддерживается исходным массивом, и ее размер нельзя изменить).

Если вы хотите удалить элементы, либо создайте, new ArrayList(Arrays.asList(..)либо удалите элементы непосредственно из массива (это будет менее эффективно и сложнее для записи)

Божо
источник
+1 Это единственно правильный ответ: Arrays.asList () возвращает неизменяемый список - вот что вызывает исключение. Это не имеет ничего общего с тем, что они «поддерживаются массивом» и т. Д. Все ArrayLists поддерживаются массивами - большое дело.
Bohemian
1
Но если вы прочтете документацию дальше, вы поймете, что ее нельзя изменить ... "Возвращает список фиксированного размера, поддерживаемый указанным массивом. (Изменения в возвращенном списке" записывают "в массив .) «-1, Этьен совершенно прав.
Стивен Шланскер
1
@Steven. Да, именно поэтому здесь написано «фиксированный размер», а не «неизменяемый» или «только для чтения». На самом деле, я сейчас отредактирую свой ответ, чтобы отразить это.
Этьен де Мартель
1
@Bohemian, возвращаемые коллекции фактически "изменяемы", потому что можно вызвать метод "set".
javalearner
2
Если вы собираетесь подбирать такие гниды, вы можете с тем же успехом сказать банальные вещи вроде «он выдает исключение UnsupportedOperationException, потому что в коде есть оператор throw UnsupportedOperationException». Потребителей API не волнует, какой суперкласс AbstractBlah генерирует исключение, им важны контракты и ожидания используемого класса. В JVM v + 1 вполне возможно, что библиотека классов изменится при возникновении исключения, но контракт не изменится.
Стивен Шланскер
7

Этот способ Array.asList()работает, потому что он напрямую поддерживается массивом. Чтобы получить полностью изменяемый список, вам нужно будет клонировать коллекцию в коллекцию, созданную вами.

Collection c = new ArrayList(Arrays.asList(la))
Хенко
источник
1
Список можно изменить, но только через set (). возвращенная коллекция имеет фиксированный размер.
javalearner
Я никогда не говорил, что его нельзя изменить. Просто чтобы получить (полностью) изменяемый список, вам нужно будет использовать файл ArrayList. Хотя, возможно, разница была не слишком очевидной. :-) Является ли список изменяемым или нет - это вопрос определения, он "полумодифицируемый", но не полностью изменяемый, на мой взгляд.
henko