由Arrays.asList()创建的List执行remove()操作会抛出UnsupportedOperationException异常。

100
我有一个 c1<MyClass> 集合和一个 a<MyClass> 数组。我试图将数组转换为集合 c2 并执行 c1.removeAll(c2),但这会抛出 UnsupportedOperationException 异常。我发现 Arrays 类的 asList() 方法返回 Arrays.ArrayList 类,并且此类继承自 AbstractList(),其实现会抛出 UnsupportedOperationException 异常。
    Myclass la[] = getMyClass();
    Collection c = Arrays.asList(la);
    c.removeAll(thisAllreadyExistingMyClass);

有没有办法删除这些元素?请帮忙。


相关问题:https://dev59.com/uHA85IYBdhLWcg3wCfHm - RamValli
3个回答

192

Arrays.asList 返回一个围绕数组的 List 包装器。该包装器具有固定大小并直接由数组支持,因此对 set 的调用将修改数组,并且任何修改列表的其他方法都将引发 UnsupportedOperationException

要解决此问题,您必须通过复制包装器列表的内容来创建一个新的可修改列表。可以使用接受 CollectionArrayList 构造函数轻松实现此操作:

Collection c = new ArrayList(Arrays.asList(la));

3
我在查看java.util.Arrays中的asList()方法源代码时发现它似乎返回一个ArrayList。但是,当我执行System.out.println(list.getClass())时,输出结果为class java.util.Arrays$ArrayList。它使用了内部的ArrayList类,该类没有addremove方法。我只是想知道为什么要有一个内部的ArrayList类,而不使用java.util.ArrayList,以及为什么没有add()remove()方法? - Honinbo Shusaku
更正我之前的评论:它确实有一个addremove方法。 - Honinbo Shusaku
1
@Abdul 因为 java.util.ArrayList 没有固定大小,所以不存在这样的东西。你需要一个实现 List 接口的类,如果你对它执行非法操作(例如添加或删除),就会抛出异常,而 ArrayList 并不满足该要求。 - Etienne de Martel
@Abdul Arrays.asList 只是创建了一个包装器 List。但它仍然是一个 java.util.List,因此必须具有这些方法。但是它们不能被应用,因为那将导致创建一个具有不同大小的新数组。这是不可能的,因为您仍然可以通过返回的 List 和原始数组进行修改。如果返回的 List 可以更改,以至于它基本上会丢弃原始数组引用,那么这将是不可能的。 - Adam Hošek

16

没错,Arrays.asList(..)是一种不能扩展或缩小的集合(因为它是由原始数组支持的,而且它的大小不能改变)。

如果你想删除元素,可以创建一个new ArrayList(Arrays.asList(..),或者直接从数组中删除元素(这将更低效且更难编写)。


1
但是如果你仔细阅读文档,你会意识到它实际上是可修改的... "返回由指定数组支持的固定大小列表。(对返回的列表所做的更改将写入数组。)" -1,Etienne 是完全正确的。 - Steven Schlansker
1
@Steven 是的,这就是为什么它说“固定大小”而不是“不可修改”或“只读”。实际上,我现在会去编辑我的答案以反映这一点。 - Etienne de Martel
1
@Bohemian,返回的集合实际上是“可修改的”,因为可以调用“set”方法。 - javalearner
2
如果你要像那样挑毛病,你可能会说一些空洞的话,比如“它抛出UnsupportedOperationException是因为代码中有一个throw UnsupportedOperationException语句”。API的使用者并不关心哪个AbstractBlah超类抛出了异常,他们关心所使用的类的合同和期望。在JVM v+1中,类库完全可以改变异常抛出的位置,但合同不会改变。 - Steven Schlansker
我正在查看java.util.Arrays的源代码中的asList()方法,它似乎返回一个ArrayList。然而,当我执行System.out.println(list.getClass());时,我得到了class java.util.Arrays$ArrayList。因此,它使用内部的ArrayList类,该类没有addremove方法。我只是想知道为什么要有一个内部的ArrayList类,而不是使用java.util.ArrayList,为什么没有add()remove()方法? - Honinbo Shusaku
显示剩余9条评论

8
那就是Array.asList()的工作方式,因为它直接由数组支持。要获取完全可修改的列表,您需要将集合克隆到自己创建的集合中。
Collection c = new ArrayList(Arrays.asList(la))

1
该列表可通过set()进行修改,但返回的集合是固定大小的。 - javalearner
我从未说过它是不可修改的。只是为了获得一个(完全)可修改的列表,您必须使用ArrayList。然而,区别可能不太明显。 :-) 列表是否可修改是一个定义问题,在我看来它是“半可修改的”,但并非完全可修改。 - henko

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接