为什么当我试图从列表中删除一个元素时,我得到一个UnsupportedOperationException ?

我有这样的代码:

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)

这样做是正确的吗?Java.15

574972 次浏览

可能是因为您正在使用无法改变的包装

更改这一行:

List<String> list = Arrays.asList(split);

到这一行:

List<String> list = new LinkedList<>(Arrays.asList(split));
这个问题已经困扰我很多次了。Arrays.asList创建一个不可修改的列表。 返回由指定数组支持的固定大小列表

创建一个具有相同内容的新列表:

newList.addAll(Arrays.asList(newArray));

这将产生一些额外的垃圾,但您将能够对其进行突变。

Arrays.asList()返回的列表可能是不可变的。你能试试吗?

List<String> list = new ArrayList<>(Arrays.asList(split));

只需阅读JavaDoc中的asList方法:

返回对象的{@code List} 在指定数组中。的大小 {@code List}不能被修改, 即添加和删除是 不支持,但元素可以支持 集。元素的设置将修改 底层数组。< / p >

这是来自Java 6,但它看起来是一样的android Java。

编辑

结果列表的类型是Arrays.ArrayList,它是Arrays.class中的一个私有类。实际上,它只不过是您通过Arrays.asList传递的数组的List-view。结果是:如果你改变了数组,列表也会改变。并且由于数组不能重新调整大小,因此不支持删除和添加操作必须

Arrays.asList()返回一个不允许操作影响其大小的列表(注意,这与“不可修改”不同)。

你可以做new ArrayList<String>(Arrays.asList(split));来创建一个真实的副本,但看到你正在尝试做什么,这里有一个额外的建议(你有一个O(n^2)算法在下面)。

您想要从列表中删除list.size() - count(让我们称之为k)随机元素。只是选择尽可能多的随机元素,并将它们交换到列表的k结尾位置,然后删除整个范围(例如使用subList()和clear())。这将把它变成一个精简和平均的O(n)算法(O(k)更精确)。

更新:如下所述,这个算法只在元素是无序的情况下才有意义,例如,如果List表示一个Bag。另一方面,如果List具有有意义的顺序,则该算法不会保留它(polygeneluants的算法会保留它)。

更新2:所以回想起来,一个更好的(线性,保持顺序,但有O(n)个随机数)算法应该是这样的:

LinkedList<String> elements = ...; //to avoid the slow ArrayList.remove()
int k = elements.size() - count; //elements to select/delete
int remaining = elements.size(); //elements remaining to be iterated
for (Iterator i = elements.iterator(); k > 0 && i.hasNext(); remaining--) {
i.next();
if (random.nextInt(remaining) < k) {
//or (random.nextDouble() < (double)k/remaining)
i.remove();
k--;
}
}

你的代码有很多问题:

Arrays.asList上返回固定大小的列表

来自API:

Arrays.asList:返回指定数组支持的固定大小的列表

你不能add到它;你不能从它remove。你不能在结构上修改List

修复

创建LinkedList,它支持更快的remove

List<String> list = new LinkedList<String>(Arrays.asList(split));

split取正则表达式

来自API:

String.split(String regex):围绕给定的正则表达式进行拆分。

|是一个正则元字符;如果你想要分割一个文字|,你必须将它转义到\|,作为一个Java字符串文字是"\\|"

解决办法:

template.split("\\|")

更好的算法

与其使用随机索引一次调用一个remove,不如在范围内生成足够多的随机数,然后使用listIterator()遍历List,在适当的索引处调用remove()。关于如何在给定范围内生成随机但不同的数字,有关于stackoverflow的问题。

这样,您的算法将是O(N)

这个UnsupportedOperationException发生在你试图对不允许的集合执行一些操作时,在你的情况下,当你调用Arrays.asList时,它不会返回java.util.ArrayList。它返回一个java.util.Arrays$ArrayList,这是一个不可变列表。你不能向它添加,也不能从它删除。

不能向固定大小的数组列表中删除或添加数组。

但您可以从该列表创建子列表。

# EYZ0

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 = list.subList(0, list.size() - (list.size() - count));
}
return StringUtils.join(list, ", ");
}

*另一种方法是

ArrayList<String> al = new ArrayList<String>(Arrays.asList(template));

这将创建数组列表,它不像Arrays.asList那样是固定大小的

我认为取代:

List<String> list = Arrays.asList(split);

List<String> list = new ArrayList<String>(Arrays.asList(split));

解决问题。

是的,在Arrays.asList上,返回一个固定大小的列表。

除了使用链表,只需使用addAll方法列表。

例子:

String idList = "123,222,333,444";


List<String> parentRecepeIdList = new ArrayList<String>();


parentRecepeIdList.addAll(Arrays.asList(idList.split(",")));


parentRecepeIdList.add("555");

对于这个问题,我有另一个解决方案:

List<String> list = Arrays.asList(split);
List<String> newList = new ArrayList<>(list);

工作在newList;)

以下是来自Arrays的代码片段

public static <T> List<T> asList(T... a) {
return new ArrayList<>(a);
}


/**
* @serial include
*/
private static class ArrayList<E> extends AbstractList<E>
implements RandomAccess, java.io.Serializable
{
private static final long serialVersionUID = -2764017481108945198L;
private final E[] a;

所以当asList方法被调用时,它会返回它自己的私有静态类版本的列表,它不会覆盖AbstractList中的add函数来将元素存储在数组中。默认情况下,抽象列表中的add方法会抛出异常。

所以它不是正则数组列表。

取代

List<String> list=Arrays.asList(split);

List<String> list = New ArrayList<>();
list.addAll(Arrays.asList(split));

List<String> list = new ArrayList<>(Arrays.asList(split));

List<String> list = new ArrayList<String>(Arrays.asList(split));

或(更适合删除元素)

List<String> list = new LinkedList<>(Arrays.asList(split));

Arrays.asList()内部使用固定大小的数组 您不能动态地添加或删除Arrays.asList()

使用这个

Arraylist<String> narraylist=new ArrayList(Arrays.asList());

narraylist中,您可以轻松地添加或删除项目。

< p > Arraylist narraylist = arrays . aslist ();//返回不可变数组列表 使其可变的解决方案将是: Arraylist naraylist =new Arraylist (Arrays.asList());

创建一个新列表并在新列表中填充有效值对我来说很有用。

代码抛出错误-

List<String> list = new ArrayList<>();
for (String s: list) {
if(s is null or blank) {
list.remove(s);
}
}
desiredObject.setValue(list);

修复后-

 List<String> list = new ArrayList<>();
List<String> newList= new ArrayList<>();
for (String s: list) {
if(s is null or blank) {
continue;
}
newList.add(s);
}
desiredObject.setValue(newList);
问题是你正在使用数组. aslist()方法创建一个具有固定长度的列表 这意味着< / p >

由于返回的List是一个固定大小的List,所以不能添加/删除元素。

请看下面我正在使用的代码块

由于它是由asList()创建的迭代列表,因此不可能删除和添加,它是一个固定数组

List<String> words = Arrays.asList("pen", "pencil", "sky", "blue", "sky", "dog");
for (String word : words) {
if ("sky".equals(word)) {
words.remove(word);
}
}

这将很好地工作,因为我们正在获取一个新的数组列表,我们可以在迭代时进行修改

List<String> words1 = new ArrayList<String>(Arrays.asList("pen", "pencil", "sky", "blue", "sky", "dog"));
for (String word : words) {
if ("sky".equals(word)) {
words.remove(word);
}
}