Por que recebo uma UnsupportedOperationException ao tentar remover um elemento de uma lista?

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

Eu entendi isso:

 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) 

Como seria esse o caminho correto? Java.15

Alguns problemas com o seu código:

Em Arrays.asList retornando uma lista de tamanho fixo

Da API:

Arrays.asList : retorna uma lista de tamanho fixo respaldada pela matriz especificada.

Você não pode add a isso; você não pode remove dele. Você não pode modificar estruturalmente a List .

Consertar

Crie um LinkedList , que suporta remove mais rápida.

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

Na split tomando regex

Da API:

String.split(String regex) : Divide essa string em torno das correspondências da expressão regular dada.

| é um metacaractere de expressão regular; se você quiser dividir em um literal | , você deve escaping para \| , que como um literal de string Java é "\\|" .

Consertar:

 template.split("\\|") 

Em melhor algoritmo

Em vez de chamar remove um de cada vez com índices randoms, é melhor gerar números randoms suficientes no intervalo e, em seguida, percorrer a List uma vez com um listIterator() , chamando remove() nos índices apropriados. Há perguntas no stackoverflow sobre como gerar números randoms, mas distintos, em um determinado intervalo.

Com isso, seu algoritmo seria O(N) .

Este me queimou muitas vezes. Arrays.asList cria uma lista não modificável. Do Javadoc: Retorna uma lista de tamanho fixo apoiada pela matriz especificada.

Crie uma nova lista com o mesmo conteúdo:

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

Isso criará um pouco de lixo extra, mas você poderá alterá-lo.

Provavelmente porque você está trabalhando com invólucro não modificável .

Altere esta linha:

 List list = Arrays.asList(split); 

para esta linha:

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

Eu acho que substituindo:

 List list = Arrays.asList(split); 

com

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

resolve o problema.

Apenas leia o JavaDoc para o método asList:

Retorna uma {@code List} dos objects na matriz especificada. O tamanho da {@code List} não pode ser modificado, isto é, a adição e a remoção não são suportadas, mas os elementos podem ser definidos. Definir um elemento modifica o array subjacente.

Isso é do Java 6, mas parece que é o mesmo para o java android.

EDITAR

O tipo da lista resultante é Arrays.ArrayList , que é uma class privada dentro de Arrays.class. Praticamente falando, não é nada, mas uma visão de lista na matriz que você passou com Arrays.asList . Com uma conseqüência: se você alterar o array, a lista também será alterada. E como uma matriz não pode ser redimensionada, a operação de remoção e adição não deve ser suportada.

Arrays.asList () retorna uma lista que não permite operações que afetam seu tamanho (note que isso não é o mesmo que “unmodifiable”).

Você poderia fazer o new ArrayList(Arrays.asList(split)); para criar uma cópia real, mas vendo o que você está tentando fazer, aqui está uma sugestão adicional (você tem um algoritmo O(n^2) logo abaixo disso).

Você deseja remover elementos randoms list.size() - count (permite chamar isso de k ) da lista. Basta escolher quantos elementos randoms e trocá-los com as posições finais da lista, depois excluir esse intervalo inteiro (por exemplo, usando subList () e clear () sobre isso). Isso o transformaria em um algoritmo O(n) enxuto e médio ( O(k) é mais preciso).

Atualização : Conforme observado abaixo, este algoritmo só faz sentido se os elementos não estiverem desordenados, por exemplo, se a lista representa um saco. Se, por outro lado, a Lista tiver uma ordem significativa, esse algoritmo não a preservaria (o algoritmo dos poligenelubrificantes, por sua vez, o faria).

Atualização 2 : Então, em retrospecto, um algoritmo melhor (linear, mantendo a ordem, mas com números randoms O (n)) seria algo assim:

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

A lista retornada por Arrays.asList() pode ser imutável. Você poderia tentar

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

Eu tenho outra solução para esse problema:

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

trabalhar em newList 😉

Este UnsupportedOperationException vem quando você tenta executar alguma operação na coleção onde não é permitido e, no seu caso, quando você chama Arrays.asList ele não retorna um java.util.ArrayList . Ele retorna um java.util.Arrays$ArrayList que é uma lista imutável. Você não pode adicioná-lo e não pode removê-lo.

Sim, em Arrays.asList , retornando uma lista de tamanho fixo.

Além de usar uma linked list, basta usar a lista de methods addAll .

Exemplo:

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

A seguir está o snippet de código de matrizes

 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; 

então o que acontece é que quando o método asList é chamado, ele retorna uma lista de sua própria versão de class estática privada que não substitui add funcion de AbstractList para armazenar o elemento na matriz. Então, por padrão, o método add na lista abstrata lança uma exceção.

Portanto, não é uma lista de matriz regular.

Você não pode remover, nem pode adicionar a uma lista de tamanho fixo de matrizes.

Mas você pode criar sua sub-lista nessa 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, ", "); } 

* Outro caminho é

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

isso criará ArrayList que não é um tamanho fixo como Arrays.asList