100

I have a collection c1<MyClass> and an array a<MyClass>. I am trying to convert the array to a collection c2 and do c1.removeAll(c2), But this throws UnsupportedOperationException. I found that the asList() of Arrays class returns Arrays.ArrayList class and the this class inherits the removeAll() from AbstractList() whose implementation throws UnsupportedOperationException.

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

Is there any way to remove the elements? please help

Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
javalearner
  • 3,314
  • 7
  • 26
  • 33
  • related Question: http://stackoverflow.com/questions/2965747/why-i-get-unsupportedoperationexception-when-trying-to-remove-from-the-list – RamValli Mar 17 '16 at 08:54

3 Answers3

192

Arrays.asList returns a List wrapper around an array. This wrapper has a fixed size and is directly backed by the array, and as such calls to set will modify the array, and any other method that modifies the list will throw an UnsupportedOperationException.

To fix this, you have to create a new modifiable list by copying the wrapper list's contents. This is easy to do by using the ArrayList constructor that takes a Collection:

Collection c = new ArrayList(Arrays.asList(la));
Etienne de Martel
  • 34,692
  • 8
  • 91
  • 111
  • 3
    I was looking at the source code for `java.util.Arrays` `asList()` method, and it seems to return an `ArrayList`. However, when I do a `System.out.println(list.getClass());`, I get `class java.util.Arrays$ArrayList`. So it uses the inner `ArrayList` class, which doesn't have a `add` or `remove` method. I'm just wondering what's the point of having an inner `ArrayList` class instead of using the `java.util.ArrayList` one and why not have an `add()` and `remove()` method? – Honinbo Shusaku Aug 26 '15 at 15:23
  • Correction to my above comment: it does have an `add` and `remove` method – Honinbo Shusaku Aug 26 '15 at 15:33
  • 1
    @Abdul Because there is no such thing as a fixed size `java.util.ArrayList`. You want an implementation of `List` that throws an exception if you do something illegal with it (such as adding or removing), and `ArrayList` does not satisfy that requirement. – Etienne de Martel Aug 26 '15 at 19:18
  • @Abdul `Arrays.asList` just creates a wrapper `List`. But it's still a `java.util.List`, so it must have those methods. But they cannot be applied because that would lead to creating a new array with different size. Which can't be done because the modifications you can still do can be done both through the returned List and the original array. This won't be possible if the returned List could change so that it would basically throw away the original array reference. – Adam Hošek Dec 13 '17 at 21:18
16

Yup, the Arrays.asList(..) is collection that can't be expanded or shrunk (because it is backed by the original array, and it can't be resized).

If you want to remove elements either create a new ArrayList(Arrays.asList(..) or remove elements directly from the array (that will be less efficient and harder to write)

Brian Agnew
  • 268,207
  • 37
  • 334
  • 440
Bozho
  • 588,226
  • 146
  • 1,060
  • 1,140
  • +1 This answer is the only correct one: Arrays.asList() returns an *unmodifiable* list - that's what's throwing the exception. It's nothing to do with being "backed by an array" etc... *all* ArrayLists are backed by arrays - big deal. – Bohemian Oct 25 '11 at 06:58
  • @Bohemian Perhaps you should re-read my answer, then, because I think I meet your requirements. – Etienne de Martel Oct 25 '11 at 07:02
  • @Bohemian Did you really read, or did you stop at the first sentence? In fact, the doc for `asList` even states "Returns a fixed-size list backed by the specified array". It's hardly irrelevant, it's _the exact wording of the official documentation_. – Etienne de Martel Oct 25 '11 at 07:04
  • 1
    But if you'd read further into the docs, you'd realize that it is not actually unmodifiable... "Returns a fixed-size list backed by the specified array. (Changes to the returned list "write through" to the array.)" -1, Etienne is quite right. – Steven Schlansker Oct 25 '11 at 07:08
  • 1
    @Steven Yes, that's why it says "fixed size" rather than "unmodifiable" or "read only". Actually, I'll go edit my answer right now to reflect that. – Etienne de Martel Oct 25 '11 at 07:09
  • It is not implemented *because* it would be impossible to do so without violating the "fixed size" constraint. How could you implement removeAll without violating that? If the List were of variable size, I am quite sure that the wrapper would implement it. – Steven Schlansker Oct 25 '11 at 07:11
  • @Bohemian That's not rephrasing, that's a completely different meaning. And my answer is not "completely wrong", it's at worst badly worded. Exceptions are thrown because the collection has a fixed size; overriding the methods is just the technique used to enforce that contract. – Etienne de Martel Oct 25 '11 at 07:13
  • OK, let me re-phrase. Your explanation of why the exception is thrown is wrong. The `UnsupportedException` is thrown *not* because "This wrapper has a fixed size" or any other similar reason. It is thrown because the list returned from Arrays.asList extends AbstractList and doesn't override the modifier methods, which by default throw the exception - nothing to do with the backing array. Your solution however is correct. – Bohemian Oct 25 '11 at 07:15
  • 1
    @Bohemian, The returned collections is infact 'modifiable' because it is possible to call the 'set' method. – javalearner Oct 25 '11 at 07:17
  • 2
    If you're going to pick nits like that, you might as well say vapid things like "it throws UnsupportedOperationException because there is a throw UnsupportedOperationException statement in the code". Consumers of an API don't care which AbstractBlah superclass is throwing an exception, they care what the contracts and expectations of the class they use are. In JVM v+1, it is entirely possible the class library changes where the exception is thrown - but the contract will not change. – Steven Schlansker Oct 25 '11 at 07:18
  • @Bohemian Of course it's thrown because a method is overriden: that's how it's done in Java. The thing is, _why_ was the method overriden to throw an exception instead of defaulting to `ArrayList`'s behavior? Because it has a fixed size. I'm talking about design, you're talking about implementation details. – Etienne de Martel Oct 25 '11 at 07:19
  • @Steven Schlansker fixed the wording. (removed "unmodifiable") – Bozho Oct 25 '11 at 07:41
  • I was looking at the source code for `java.util.Arrays` `asList()` method, and it seems to return an `ArrayList`. However, when I do a `System.out.println(list.getClass());`, I get `class java.util.Arrays$ArrayList`. So it uses the inner `ArrayList` class, which doesn't have a `add` or `remove` method. I'm just wondering what's the point of having an inner `ArrayList` class instead of using the `java.util.ArrayList` one and why not have an `add()` and `remove()` method? – Honinbo Shusaku Aug 26 '15 at 15:23
  • Correction to my above comment: it does have an `add` and `remove` method – Honinbo Shusaku Aug 26 '15 at 15:33
8

That is the way Array.asList() works, because it is directly backed by the array. To get a fully modifiable list, you would have to clone the collection into a collection created by yourself.

Collection c = new ArrayList(Arrays.asList(la))
henko
  • 763
  • 7
  • 16
  • 1
    The list is modifiable but only through set(). the returned collection is fixed-size. – javalearner Oct 25 '11 at 08:28
  • I never actually said it was unmodifiable. Just that to get a (fully) modifiable list you would have to use an `ArrayList`. The difference perhaps wasn't too clear though. :-) Whether the list is modifiable or not is a question of definition, it is "semi-modifiable" but not fully modifiable in my view. – henko Oct 25 '11 at 11:16