¿Por qué obtengo una excepción UnsupportedOperationException cuando intento eliminar un elemento de una Lista?
Tengo este código:
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, ", ");
}
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 este el camino correcto? Java.15
12 answers
Bastantes problemas con su código:
On Arrays.asList
returning a fixed-size list
De la API:
Arrays.asList
: Devuelve un fixed-size list respaldado por el array especificado.
No puedes add
a ella; no puedes remove
de ella. No se puede modificar estructuralmente el List
.
Fix
Crear un LinkedList
, que soporta más rápido remove
.
List<String> list = new LinkedList<String>(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 metacarácter regex; si desea dividir en un literal |
, debe escaparlo a \|
, que como un literal de cadena de Java es "\\|"
.
Fix:
template.split("\\|")
En un mejor algoritmo
En lugar de llamar a remove
uno a la vez con índices aleatorios, es mejor generar suficientes números aleatorios en el rango, y luego recorriendo el List
una vez con un listIterator()
, llamando a remove()
en los índices apropiados. Hay preguntas en stackoverflow sobre cómo generar números aleatorios pero distintos en un rango dado.
Con esto, su algoritmo sería O(N)
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-06-03 12:19:15
Este me ha quemado muchas veces. Arrays.asList
crea una lista no modificable.
Desde Javadoc: Devuelve una lista de tamaño fijo respaldada por el array especificado.
Crea una nueva lista con el mismo contenido:
newList.addAll(Arrays.asList(newArray));
Esto creará un poco de basura extra, pero usted será capaz de mutar.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-10-01 16:03:43
Probablemente porque estás trabajando con envoltura no modificable.
Cambie esta línea:
List<String> list = Arrays.asList(split);
A esta línea:
List<String> list = new LinkedList<>(Arrays.asList(split));
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-12 20:40:43
Creo que reemplazar:
List<String> list = Arrays.asList(split);
Con
List<String> list = new ArrayList<String>(Arrays.asList(split));
Resuelve el problema.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-24 18:29:52
Simplemente lea el JavaDoc para el método asList:
Devuelve una {@lista de códigos} de los objetos en la matriz especificada. El tamaño de la lista de códigos {@} no se puede modificar, es decir, agregar y eliminar son sin soporte, pero los elementos pueden ser establecer. Establecer un elemento modifica el matriz subyacente.
Esto es de Java 6 pero parece que es lo mismo para Android java.
EDITAR
El tipo de la lista resultante es Arrays.ArrayList
, que es un clase privada dentro de matrices.clase. Prácticamente hablando, no es más que una vista de lista en el array que has pasado con Arrays.asList
. Con una consecuencia: si cambia la matriz, la lista también se cambia. Y debido a que un array no es redimensionable, remove and add operation debe no ser compatible.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-06-03 12:30:03
Matrices.asList () devuelve una lista que no permite operaciones que afecten su tamaño (tenga en cuenta que esto no es lo mismo que "no modificable").
Podrías hacer new ArrayList<String>(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 este k
) elementos aleatorios de la lista. Simplemente elija tantos elementos aleatorios y cámbielos a las posiciones finales k
de la lista, entonces eliminar todo ese rango (por ejemplo, usando subList () y clear () en eso). Eso lo convertiría en un algoritmo lean y mean O(n)
(O(k)
es más preciso).
Update: Como se indica a continuación, este algoritmo solo tiene sentido si los elementos no están ordenados, por ejemplo, si la Lista representa una Bolsa. Si, por otro lado, la Lista tiene un orden significativo, este algoritmo no preservarla (polygenelubricants' algoritmo contrario).
Actualización 2: Así que en retrospectiva, una mejor (lineal, manteniendo el orden, pero con O (n) números aleatorios) algoritmo sería algo como esto:
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--;
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-06-03 13:03:53
La lista devuelta por Arrays.asList()
podría ser inmutable. Podría intentar
List<String> list = new ArrayList(Arrays.asList(split));
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-12 20:41:20
Tengo otra solución para ese problema:
List<String> list = Arrays.asList(split);
List<String> newList = new ArrayList<>(list);
Trabajo sobre newList
;)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-12 20:40:58
Esta excepción UnsupportedOperationException se produce 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 se puede añadir y no se puede quitar de ella.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-06-03 13:30:40
Sí, en Arrays.asList
, devolviendo una lista de tamaño fijo.
Aparte de usar una lista vinculada, simplemente use addAll
lista de métodos.
Ejemplo:
String idList = "123,222,333,444";
List<String> parentRecepeIdList = new ArrayList<String>();
parentRecepeIdList.addAll(Arrays.asList(idList.split(",")));
parentRecepeIdList.add("555");
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-12 20:42:22
A continuación se muestra un fragmento de código de 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;
Entonces, lo que sucede es que cuando se llama al método asList, devuelve la lista de su propia versión de clase estática privada que no reemplaza la función add de AbstractList para almacenar el elemento en una matriz. Así que por defecto agregar método en lista abstracta lanza excepción.
Así que no es una lista de matrices regular.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-04-15 04:10:13
No se puede eliminar, ni se puede agregar a una lista de matrices de tamaño fijo.
Pero puedes crear tu sublista a partir de esa lista.
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, ", ");
}
*Otra forma es
ArrayList<String> al = new ArrayList<String>(Arrays.asList(template));
Esto creará ArrayList que no es de tamaño fijo como los Arrays.asList
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-12 20:42:09