Why do I get an UnsupportedOperationException when

2018-12-31 09:10发布

I have this code:

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, ", ");
}

I get this:

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)

How would be this the correct way? Java.15

13条回答
墨雨无痕
2楼-- · 2018-12-31 09:32

Just read the JavaDoc for the asList method:

Returns a {@code List} of the objects in the specified array. The size of the {@code List} cannot be modified, i.e. adding and removing are unsupported, but the elements can be set. Setting an element modifies the underlying array.

This is from Java 6 but it looks like it is the same for the android java.

EDIT

The type of the resulting list is Arrays.ArrayList, which is a private class inside Arrays.class. Practically speaking, it is nothing but a List-view on the array that you've passed with Arrays.asList. With a consequence: if you change the array, the list is changed too. And because an array is not resizeable, remove and add operation must be unsupported.

查看更多
千与千寻千般痛.
3楼-- · 2018-12-31 09:33

I've got another solution for that problem:

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

work on newList ;)

查看更多
ら面具成の殇う
4楼-- · 2018-12-31 09:34

Probably because you're working with unmodifiable wrapper.

Change this line:

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

to this line:

List<String> list = new LinkedList<>(Arrays.asList(split));
查看更多
呛了眼睛熬了心
5楼-- · 2018-12-31 09:38

Quite a few problems with your code:

On Arrays.asList returning a fixed-size list

From the API:

Arrays.asList: Returns a fixed-size list backed by the specified array.

You can't add to it; you can't remove from it. You can't structurally modify the List.

Fix

Create a LinkedList, which supports faster remove.

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

On split taking regex

From the API:

String.split(String regex): Splits this string around matches of the given regular expression.

| is a regex metacharacter; if you want to split on a literal |, you must escape it to \|, which as a Java string literal is "\\|".

Fix:

template.split("\\|")

On better algorithm

Instead of calling remove one at a time with random indices, it's better to generate enough random numbers in the range, and then traversing the List once with a listIterator(), calling remove() at appropriate indices. There are questions on stackoverflow on how to generate random but distinct numbers in a given range.

With this, your algorithm would be O(N).

查看更多
唯独是你
6楼-- · 2018-12-31 09:38

I think that replacing:

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

with

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

resolves the problem.

查看更多
有味是清欢
7楼-- · 2018-12-31 09:40

The list returned by Arrays.asList() might be immutable. Could you try

List<String> list = new ArrayList(Arrays.asList(split));
查看更多
登录 后发表回答