¿Por qué recibo una UnsupportedOperationException cuando bash eliminar un elemento de una lista?

Tengo este código:

public static String SelectRandomFromTemplate(String template,int count) { String[] split = template.split("|"); List list=Arrays.asList(split); Random r = new Random(); while( list.size() > count ) { list.remove(r.nextInt(list.size())); } return StringUtils.join(list, ", "); } 

Entiendo esto:

 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) 

¿Cómo sería esta la manera correcta? Java.15

Muy pocos problemas con su código:

En Arrays.asList devuelve una lista de tamaño fijo

De la API:

Arrays.asList : devuelve una lista de tamaño fijo respaldada por la matriz especificada.

No puedes add ; no puedes remove No puedes modificar estructuralmente la List .

Fijar

Cree una LinkedList que admita una remove más rápida.

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

En split tomando regex

De la API:

String.split(String regex) : divide esta cadena alrededor de las coincidencias de la expresión regular dada.

| es un metacaracter regex; si quieres dividir en un literal | , debes escapar a \| , que como un literal de cadena de Java es "\\|" .

Fijar:

 template.split("\\|") 

En un mejor algoritmo

En lugar de llamar remove uno a la vez con índices aleatorios, es mejor generar suficientes números aleatorios en el rango, y luego recorrer la List una vez con un listIterator() , llamando a remove() en los índices apropiados. Hay preguntas sobre stackoverflow sobre cómo generar números aleatorios pero distintos en un rango dado.

Con esto, tu algoritmo sería O(N) .

Este me ha quemado muchas veces. Arrays.asList crea una lista no modificable. Desde Javadoc: devuelve una lista de tamaño fijo respaldada por la matriz especificada.

Crea una nueva lista con el mismo contenido:

 newList.addAll(Arrays.asList(newArray)); 

Esto creará un poco de basura extra, pero podrás mutarlo.

Probablemente porque estás trabajando con un envoltorio no modificable .

Cambiar esta línea:

 List list = Arrays.asList(split); 

a esta línea:

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

Creo que reemplazando:

 List list = Arrays.asList(split); 

con

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

resuelve el problema

Simplemente lea JavaDoc para el método asList:

Devuelve una {@code List} de los objetos en la matriz especificada. El tamaño de la {@code List} no se puede modificar, es decir, agregar y eliminar no es compatible, pero los elementos se pueden configurar. Establecer un elemento modifica la matriz subyacente.

Esto es de Java 6 pero parece que es el mismo para el Java de Android.

EDITAR

El tipo de la lista resultante es Arrays.ArrayList , que es una clase privada dentro de Arrays.class. En términos prácticos, no es más que una vista de lista en la matriz que ha pasado con Arrays.asList . Con una consecuencia: si cambia la matriz, la lista también se cambia. Y debido a que una matriz no es redimensionable, la operación de eliminar y agregar no debe ser respaldada.

Arrays.asList () devuelve una lista que no permite que las operaciones afecten su tamaño (tenga en cuenta que esto no es lo mismo que “no modificable”).

Puede hacer una new ArrayList(Arrays.asList(split)); para crear una copia real, pero viendo lo que estás tratando de hacer, aquí hay una sugerencia adicional (tienes un algoritmo O(n^2) justo debajo de eso).

Desea eliminar list.size() - count (llamemos a esto k ) elementos aleatorios de la lista. Simplemente elija tantos elementos aleatorios y cámbielos a las posiciones k finales de la lista, luego elimine ese rango completo (por ejemplo, usando subList () y clear () sobre eso). Eso lo convertiría en un algoritmo O(n) pobre y medio ( O(k) es más preciso).

Actualización : Como se indica a continuación, este algoritmo solo tiene sentido si los elementos están desordenados, por ejemplo, si la Lista representa una Bolsa. Si, por otro lado, la Lista tiene un orden significativo, este algoritmo no lo preservaría (en cambio, el algoritmo de polygenelubricants lo haría).

Actualización 2 : Entonces, en retrospectiva, un algoritmo mejor (lineal, mantener el orden, pero con O (n) números aleatorios) sería algo como esto:

 LinkedList 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--; } } 

La lista devuelta por Arrays.asList() puede ser inmutable. Podrías probar

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

Tengo otra solución para ese problema:

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

trabajar en newList 😉

Esta UnsupportedOperationException viene cuando intenta realizar alguna operación en la colección donde no está permitido y en su caso, cuando llama a Arrays.asList no devuelve un java.util.ArrayList . Devuelve un java.util.Arrays$ArrayList que es una lista inmutable. No puede agregarle nada y no puede eliminarlo.

Sí, en Arrays.asList , devolviendo una lista de tamaño fijo.

Además de usar una lista vinculada, simplemente use addAll method list.

Ejemplo:

 String idList = "123,222,333,444"; List parentRecepeIdList = new ArrayList(); parentRecepeIdList.addAll(Arrays.asList(idList.split(","))); parentRecepeIdList.add("555"); 

Lo siguiente es un fragmento de código de matrices

 public static  List asList(T... a) { return new ArrayList<>(a); } /** * @serial include */ private static class ArrayList extends AbstractList implements RandomAccess, java.io.Serializable { private static final long serialVersionUID = -2764017481108945198L; private final E[] a; 

Entonces, ¿qué ocurre si se llama al método asList y luego devuelve la lista de su propia versión privada de clases estáticas que no anula la función de adición de AbstractList para almacenar elementos en el conjunto? Entonces, de forma predeterminada, agregar el método en la lista de resúmenes genera una excepción.

Por lo tanto, no es una lista de matriz normal.

No puede eliminar, ni puede agregar a una lista de tamaño fijo de matrices.

Pero puedes crear tu sublista desde esa lista.

list = list.subList(0, list.size() - (list.size() - count));

 public static String SelectRandomFromTemplate(String template, int count) { String[] split = template.split("\\|"); List 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, ", "); } 

* Otra forma es

 ArrayList al = new ArrayList(Arrays.asList(template)); 

esto creará ArrayList que no tiene un tamaño fijo como Arrays.asList