Reputation: 207830
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
Upvotes: 629
Views: 692585
Reputation: 35226
The list returned by Arrays.asList()
might be immutable. Could you try
List<String> list = new ArrayList<>(Arrays.asList(split));
Upvotes: 28
Reputation: 71
The issue is you're creating a List using Arrays.asList() method with fixed Length meaning that
Since the returned List is a fixed-size List, we can’t add/remove elements.
See the below block of code that I am using
This iteration will give an Exception Since it is an iteration list Created by asList() so remove and add are not possible, it is a fixed array
List<String> words = Arrays.asList("pen", "pencil", "sky", "blue", "sky", "dog");
for (String word : words) {
if ("sky".equals(word)) {
words.remove(word);
}
}
This will work fine since we are taking a new ArrayList we can perform modifications while iterating
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);
}
}
Upvotes: 7
Reputation: 1
Creating a new list and populating valid values in new list worked for me.
Code throwing error -
List<String> list = new ArrayList<>();
for (String s: list) {
if(s is null or blank) {
list.remove(s);
}
}
desiredObject.setValue(list);
After fix -
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);
Upvotes: 0
Reputation: 131
Arraylist narraylist=Arrays.asList(); // Returns immutable arraylist To make it mutable solution would be: Arraylist narraylist=new ArrayList(Arrays.asList());
Upvotes: 2
Reputation: 89
Arrays.asList()
uses fixed size array internally.
You can't dynamically add or remove from thisArrays.asList()
Use this
Arraylist<String> narraylist=new ArrayList(Arrays.asList());
In narraylist
you can easily add or remove items.
Upvotes: 2
Reputation: 2214
Replace
List<String> list=Arrays.asList(split);
to
List<String> list = New ArrayList<>();
list.addAll(Arrays.asList(split));
or
List<String> list = new ArrayList<>(Arrays.asList(split));
or
List<String> list = new ArrayList<String>(Arrays.asList(split));
or (Better for Remove elements)
List<String> list = new LinkedList<>(Arrays.asList(split));
Upvotes: 4
Reputation: 17359
Yes, on Arrays.asList
, returning a fixed-size list.
Other than using a linked list, simply use addAll
method list.
Example:
String idList = "123,222,333,444";
List<String> parentRecepeIdList = new ArrayList<String>();
parentRecepeIdList.addAll(Arrays.asList(idList.split(",")));
parentRecepeIdList.add("555");
Upvotes: 3
Reputation: 157
You can't remove, nor can you add to a fixed-size-list of Arrays.
But you can create your sublist from that list.
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, ", ");
}
*Other way is
ArrayList<String> al = new ArrayList<String>(Arrays.asList(template));
this will create ArrayList which is not fixed size like Arrays.asList
Upvotes: 2
Reputation: 1954
I've got another solution for that problem:
List<String> list = Arrays.asList(split);
List<String> newList = new ArrayList<>(list);
work on newList
;)
Upvotes: 4
Reputation: 66156
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));
Upvotes: 79
Reputation: 21381
I think that replacing:
List<String> list = Arrays.asList(split);
with
List<String> list = new ArrayList<String>(Arrays.asList(split));
resolves the problem.
Upvotes: 16
Reputation: 17453
Following is snippet of code from 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;
so what happens is that when asList method is called then it returns list of its own private static class version which does not override add funcion from AbstractList to store element in array. So by default add method in abstract list throws exception.
So it is not regular array list.
Upvotes: 1
Reputation: 3663
This one has burned me many times. Arrays.asList
creates an unmodifiable list.
From the Javadoc: Returns a fixed-size list backed by the specified array.
Create a new list with the same content:
newList.addAll(Arrays.asList(newArray));
This will create a little extra garbage, but you will be able to mutate it.
Upvotes: 182
Reputation: 41
This UnsupportedOperationException comes when you try to perform some operation on collection where its not allowed and in your case, When you call Arrays.asList
it does not return a java.util.ArrayList
. It returns a java.util.Arrays$ArrayList
which is an immutable list. You cannot add to it and you cannot remove from it.
Upvotes: 4
Reputation: 8898
Arrays.asList() returns a list that doesn't allow operations affecting its size (note that this is not the same as "unmodifiable").
You could do new ArrayList<String>(Arrays.asList(split));
to create a real copy, but seeing what you are trying to do, here is an additional suggestion (you have a O(n^2)
algorithm right below that).
You want to remove list.size() - count
(lets call this k
) random elements from the list. Just pick as many random elements and swap them to the end k
positions of the list, then delete that whole range (e.g. using subList() and clear() on that). That would turn it to a lean and mean O(n)
algorithm (O(k)
is more precise).
Update: As noted below, this algorithm only makes sense if the elements are unordered, e.g. if the List represents a Bag. If, on the other hand, the List has a meaningful order, this algorithm would not preserve it (polygenelubricants' algorithm instead would).
Update 2: So in retrospect, a better (linear, maintaining order, but with O(n) random numbers) algorithm would be something like this:
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--;
}
}
Upvotes: 4
Reputation: 114757
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.
Upvotes: 6
Reputation: 383676
Quite a few problems with your code:
Arrays.asList
returning a fixed-size listFrom 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
.
Create a LinkedList
, which supports faster remove
.
List<String> list = new LinkedList<String>(Arrays.asList(split));
split
taking regexFrom 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 "\\|"
.
template.split("\\|")
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)
.
Upvotes: 1234