我有这个代码:
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
13 回答
以下是Arrays的代码片段
所以会发生的事情是,当调用asList方法时,它会返回自己的私有静态类版本的列表,该版本不会覆盖从AbstractList添加函数以将元素存储在数组中 . 因此,默认情况下,抽象列表中的add方法会抛出异常 .
所以它不是常规数组列表 .
这个烧了我好几次 .
Arrays.asList
创建一个不可修改的列表 . 从Javadoc:返回由指定数组支持的固定大小的列表 .创建具有相同内容的新列表:
这会产生一些额外的垃圾,但你可以改变它 .
Arrays.asList()
返回的列表可能是不可变的 . 你能试试吗?当您尝试在不允许的情况下对集合执行某些操作时会出现此UnsupportedOperationException,在您的情况下,当您调用
Arrays.asList
时,它不会返回java.util.ArrayList
. 它返回java.util.Arrays$ArrayList
,这是一个不可变列表 . 您无法添加它,也无法从中删除 .是的,在
Arrays.asList
上,返回一个固定大小的列表 .除了使用链接列表,只需使用
addAll
方法列表 .Example:
可能是因为你正在使用unmodifiable wrapper .
改变这一行:
到这一行:
Arrays.asList()返回一个不允许操作影响其大小的列表(请注意,这与“不可修改”不同) .
你可以做
new ArrayList<String>(Arrays.asList(split));
来创建一个真正的副本,但是看看你想要做什么,这里有一个额外的建议(你的下面有一个O(n^2)
算法) .您想要从列表中删除
list.size() - count
(让我们调用此k
)随机元素 . 只需选择尽可能多的随机元素并将它们交换到列表的末尾k
位置,然后删除整个范围(例如,使用subList()和clear()) . 这将把它变成一个精简和平均O(n)
算法(O(k)
更精确) .Update :如下所述,该算法仅在元素无序时才有意义,例如:如果List代表Bag . 另一方面,如果List具有有意义的顺序,则该算法不会保留它(polygenelubricants的算法将改为) .
Update 2 :回想起来,更好的(线性,维持顺序,但使用O(n)随机数)算法将是这样的:
您无法删除,也无法添加固定大小的数组列表 .
But you can create your sublist from that list.
list = list.subList(0, list.size() - (list.size() - count));
*其他方式是
这将创建不像Arrays.asList那样固定大小的ArrayList
你的代码有很多问题:
在Arrays.asList上返回固定大小的列表
来自API:
你不能
add
它;你不能remove
. 您无法在结构上修改List
.修复
创建一个
LinkedList
,它支持更快remove
.关于拆分采用正则表达式
来自API:
|
是一个正则表达式元字符;如果要拆分文字|
,则必须将其转义为\|
,它作为Java字符串文字"\\|"
.修复:
关于更好的算法
不是一次用随机索引调用
remove
,而是最好在范围内生成足够的随机数,然后使用listIterator()
遍历List
,在适当的索引处调用remove()
. 关于如何在给定范围内生成随机但不同的数字的stackoverflow存在问题 .有了这个,你的算法将是
O(N)
.我认为更换:
同
解决了这个问题 .
更换
至
要么
要么
或(更适合删除元素)
只需阅读JavaDoc for asList方法:
这是来自Java 6,但看起来它与android java相同 .
EDIT
结果列表的类型是
Arrays.ArrayList
,它是Arrays.class中的私有类 . 实际上,它只是你用Arrays.asList
传递的数组上的List-view . 结果是:如果更改数组,列表也会更改 . 并且因为数组不可调整大小,所以必须不支持删除和添加操作 .我有另一个问题的解决方案:
工作
newList
;)