Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do I get an UnsupportedOperationException when trying to remove an element from a List?

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

like image 833
Pentium10 Avatar asked Jun 03 '10 12:06

Pentium10


People also ask

What is UnsupportedOperationException in Java?

public class UnsupportedOperationException extends RuntimeException. Thrown to indicate that the requested operation is not supported. This class is a member of the Java Collections Framework.

What is remove ArrayList?

remove(int index) method removes the element at the specified position in this list. Shifts any subsequent elements to the left (subtracts one from their indices).


2 Answers

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).

like image 131
polygenelubricants Avatar answered Oct 22 '22 15:10

polygenelubricants


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.

like image 21
Nick Orton Avatar answered Oct 22 '22 14:10

Nick Orton