我有这段代码:
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
答案 0 :(得分:891)
您的代码存在一些问题:
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)
:将此字符串拆分为给定regular expression的匹配项。
|
是一个正则表达式元字符;如果要拆分文字|
,则必须将其转义为\|
,它作为Java字符串文字为"\\|"
。
template.split("\\|")
不是一次使用随机索引调用remove
,而是最好在范围内生成足够的随机数,然后使用List
遍历listIterator()
一次,调用{ {1}}适当的指数。关于如何在给定范围内生成随机但不同的数字的stackoverflow存在问题。
这样,您的算法将是remove()
。
答案 1 :(得分:121)
这一次烧了我很多次。 Arrays.asList
创建一个不可修改的列表。
从Javadoc:返回由指定数组支持的固定大小列表。
创建具有相同内容的新列表:
newList.addAll(Arrays.asList(newArray));
这会产生一些额外的垃圾,但你可以改变它。
答案 2 :(得分:45)
可能是因为您正在使用unmodifiable wrapper。
更改此行:
List<String> list = Arrays.asList(split);
到这一行:
List<String> list = new LinkedList<>(Arrays.asList(split));
答案 3 :(得分:11)
我认为更换:
List<String> list = Arrays.asList(split);
与
List<String> list = new ArrayList<String>(Arrays.asList(split));
解决了这个问题。
答案 4 :(得分:4)
Arrays.asList()返回一个不允许影响其大小的操作的列表(请注意,这与“unmodifiable”不同)。
你可以new ArrayList<String>(Arrays.asList(split));
创建一个真正的副本,但是看看你想要做什么,这里有一个额外的建议(你下面有一个O(n^2)
算法)。
您想要从列表中删除list.size() - count
(让我们调用此k
)个随机元素。只需选择尽可能多的随机元素并将它们交换到列表的末尾k
位置,然后删除整个范围(例如,使用subList()和clear())。这会将其变为精简且平均O(n)
算法(O(k)
更精确)。
更新:如下所述,此算法仅在元素无序时才有意义,例如:如果List代表Bag。另一方面,如果List有一个有意义的顺序,这个算法就不会保留它(polygenelubricants的算法反而会)。
更新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--;
}
}
答案 5 :(得分:4)
只需阅读JavaDoc for asList方法:
返回对象的{@code List} 在指定的数组中。的大小 {@code List}无法修改, 即添加和删除 不受支持,但元素可以 组。设置元素会修改 底层数组。
这是来自Java 6,但看起来它与android java相同。
修改强>
结果列表的类型是Arrays.ArrayList
,它是Arrays.class中的私有类。实际上,它只是您使用Arrays.asList
传递的数组上的List视图。结果是:如果更改数组,列表也会更改。并且因为数组不可调整大小,所以删除和添加操作必须不受支持。
答案 6 :(得分:4)
Arrays.asList()
返回的列表可能是不可变的。你能试试吗
List<String> list = new ArrayList(Arrays.asList(split));
答案 7 :(得分:3)
我已经为这个问题找到了另一个解决方案:
List<String> list = Arrays.asList(split);
List<String> newList = new ArrayList<>(list);
处理newList
;)
答案 8 :(得分:2)
当您尝试在不允许的情况下对集合执行某些操作时会出现此UnsupportedOperationException,在您的情况下,当您致电Arrays.asList
时,它不会返回java.util.ArrayList
。它返回一个java.util.Arrays$ArrayList
,它是一个不可变列表。您无法添加它,也无法从中删除。
答案 9 :(得分:2)
是的,在Arrays.asList
上,返回固定大小的列表。
除了使用链接列表外,只需使用addAll
方法列表。
示例:强>
String idList = "123,222,333,444";
List<String> parentRecepeIdList = new ArrayList<String>();
parentRecepeIdList.addAll(Arrays.asList(idList.split(",")));
parentRecepeIdList.add("555");
答案 10 :(得分:1)
您无法删除,也无法添加固定大小的数组列表。
但您可以从该列表中创建子列表。
list = list.subList(0, list.size() - (list.size() - count));
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
那样固定大小的ArrayList答案 11 :(得分:1)
以下是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方法会抛出异常。
所以它不是常规数组列表。
答案 12 :(得分:1)
替换
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));
答案 13 :(得分:0)
Arrays.asList()
在内部使用固定大小的数组。
您不能为此动态添加或删除Arrays.asList()
使用此
Arraylist<String> narraylist=new ArrayList(Arrays.asList());
在narraylist
中,您可以轻松添加或删除项目。
答案 14 :(得分:0)
Arraylist narraylist = Arrays.asList(); //返回不可变的arraylist 使它可变的解决方案是: Arraylist narraylist = new ArrayList(Arrays.asList());
答案 15 :(得分:0)
创建新列表并在新列表中填充有效值对我来说很有效。
代码抛出错误-
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);
答案 16 :(得分:0)
问题是您使用固定长度的Arrays.asList()方法创建列表 意思是
由于返回的列表是固定大小的列表,因此我们无法添加/删除元素。
请参阅以下我正在使用的代码块
此迭代将产生异常,因为它是由asList()创建的迭代列表,因此无法进行删除和添加,它是一个固定数组
List<String> words = Arrays.asList("pen", "pencil", "sky", "blue", "sky", "dog");
for (String word : words) {
if ("sky".equals(word)) {
words.remove(word);
}
}
这将很好用,因为我们采用了新的ArrayList,我们可以在迭代时执行修改
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);
}
}