尝试从Array.asList返回的列表中删除时出现UnsupportedOperationException

49

我正在使用一个List来保存通过调用Array.asList()方法获取的一些数据。然后我尝试使用myList.Remove(int i)方法删除一个元素。但是在尝试执行此操作时,我遇到了UnsupportedOperationException。这是什么原因?我应该如何解决这个问题?

6个回答

77

Array.asList()将一个数组封装成了列表接口。该列表仍由该数组支持。数组是固定大小的,不支持添加或删除元素,因此包装器也不能实现这些功能。

文档没有像他们可能会做得那样清楚,但它们确实说:

返回由指定数组支持的固定大小列表。

"固定大小"应该是您无法添加或删除元素的提示 :)

虽然还有其他方法可以解决这个问题(使用其他方式从数组创建新的ArrayList)而无需额外的库,但我个人建议获取Google Collections Library(或Guava,在发布时)。然后您可以使用:

List<Integer> list = Lists.newArrayList(array);

我之所以建议这样做,是因为GCL通常是一件好事,并且值得使用。

正如在评论中提到的那样,这会对数组进行复制;列表不受原始数组支持,任何集合中的更改都不会反映在另一个集合中。


同意。然而,值得注意的是原始方法确实返回一个由原始数组支持的列表,并将更改“写入”到原始数组中。使用此方法不会返回由原始数组支持的列表,对返回的列表进行的任何更改都不会影响原始数组。 - desau
从意识形态和语义上讲,这是非常奇怪的,根据我的理解 - .asList() 方法的错误实现。它返回 List 的实现,而默认情况下,ListDynamic Array 的实现。因此,非常奇怪的是,动态数组实现是一个固定大小的数组。 - Giorgi Tsiklauri
@GiorgiTsiklauri:“默认情况下是动态数组实现”的意思是什么?在各种文档中明确记录了List<E>具有可能不受所有实现支持的操作。同样,还有静态方法(List.ofList.copyOf)返回不可修改的列表。asList()的行为完全按照文档说明,那么它怎么可能是“错误的实现”呢? - Jon Skeet
@JonSkeet,我的意思是,为什么世界上会有人使用List实现引用类型?主要原因是要有一个实现动态数组ADT的实现,公开添加和删除元素的方法。所有流行的实现(据我所知)都实现了动态数组的想法。如果某个List实例和另一个List实例在行为上有所不同,仅仅是因为它们创建的方式不同,这给我带来了相当不稳定和不一致的印象。 - Giorgi Tsiklauri
@GiorgiTsiklauri:“我的意思是,为什么世界上会有人使用列表实现引用类型。”我不确定你所说的“列表实现引用类型”是什么意思,但是使用List<E>进行只读索引访问和大小可用性有很多理由。许多List<E>的用途根本不需要它是可变的。如果有一个表达这一点的接口(例如在.NET中),那就太好了,但是List<E>是一个非常古老的接口。 - Jon Skeet
显示剩余2条评论

28

它不是java.util.ArrayListArrays.asList()返回其自己的List实现(对数组进行的更改会“写入”到该列表中)。

它是一个固定大小的列表,因此不支持删除操作。

您可以从中创建真正的ArrayList

new java.util.ArrayList<>(Arrays.asList(someArray));  

asList() 的工作方式确实很令人困惑,我必须承认。


7
请阅读Arrays.asList()的API文档:

返回由指定数组支持的固定大小列表。(对返回的列表所做的更改将“写入”到数组中。)

请注意,Javadocs中标记为“可选操作”的Collections.remove(int),意味着并非所有集合都支持它。“fixed-size list”表示您无法更改列表的大小,而remove()会更改大小,因此不受支持。

如果您想更改由Arrays.asList()生成的列表,请复制它,例如:new ArrayList(Arrays.asList(...))


6

从asList获取的实现不完全实现了List接口。我建议将列表转换为ArrayList,然后对其进行修改。

请参阅remove()


你的意思是遍历这个列表,然后在开始时将所有对象放入一个ArrayList中吗? - Chathuranga Chandrasekara
不,ArrayList构造函数需要一个Collection作为参数,所以你可以直接调用new ArrayList。 - Stefan Ernst

0

因为你得到的是只读列表。 尝试:

List newList = new ArrayList(myList);

0

使用

ArrayList 代替 List

List 元素大小固定,无法添加或删除元素。


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