web-dev-qa-db-fra.com

Pourquoi ai-je une exception UnsupportedOperationException lorsque je tente de supprimer un élément d'une liste?

J'ai ce 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, ", ");
}

J'ai compris:

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)

Comment serait-ce la bonne façon? Java.15

429
Pentium10

Quelques problèmes avec votre code:

On _Arrays.asList_ renvoyant une liste de taille fixe

De l'API:

Arrays.asList : Retourne une liste de taille fixe sauvegardée par le tableau spécifié.

Vous ne pouvez pas add à cela; vous ne pouvez pas remove partir de là. Vous ne pouvez pas modifier structurellement la List.

Réparer

Créez un LinkedList, qui supporte plus rapidement remove.

_List<String> list = new LinkedList<String>(Arrays.asList(split));
_

Sur split prenant regex

De l'API:

String.split(String regex) : scinde cette chaîne en fonction des correspondances de la donnée expression régulière .

_|_ est un métacaractère regex; si vous souhaitez fractionner un littéral _|_, vous devez l'échapper à _\|_, lequel littéral Java est _"\\|"_.

Réparer:

_template.split("\\|")
_

Sur un meilleur algorithme

Au lieu d'appeler remove avec des index aléatoires, il est préférable de générer suffisamment de nombres aléatoires dans la plage, puis de parcourir la List avec une listIterator(), en appelant remove() aux indices appropriés. Il y a des questions sur stackoverflow sur la façon de générer des nombres aléatoires mais distincts dans une plage donnée.

Avec cela, votre algorithme serait O(N).

912

Celui-ci m'a brûlé plusieurs fois. Arrays.asList crée une liste non modifiable. Depuis la Javadoc: Renvoie une liste à taille fixe sauvegardée par le tableau spécifié.

Créez une nouvelle liste avec le même contenu:

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

Cela créera une petite poubelle supplémentaire, mais vous pourrez le muter.

127
Nick Orton

Probablement parce que vous travaillez avec wrapper non modifiable .

Changer cette ligne:

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

à cette ligne:

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

Je pense que remplacer:

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

avec

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

résout le problème.

12
Salim Hamidi

La liste renvoyée par Arrays.asList() pourrait être immuable. Pourriez-vous essayer

List<String> list = new ArrayList(Arrays.asList(split));
4
Pierre

Il suffit de lire le JavaDoc pour la méthode asList:

Retourne une {@code List} des objets du tableau spécifié. La taille de la {@code List} ne peut pas être modifiée, c’est-à-dire que l’ajout et la suppression ne sont pas pris en charge, mais les éléments peuvent être définis. La définition d'un élément modifie le tableau sous-jacent.

Cela provient de Java 6, mais il semble que ce soit la même chose pour le Android Java.

EDIT

Le type de la liste résultante est Arrays.ArrayList, qui est une classe privée dans Arrays.class. En pratique, ce n'est rien qu'une vue en liste sur le tableau que vous avez passé avec Arrays.asList. Conséquence: si vous modifiez le tableau, la liste est également modifiée. Et comme un tableau n'est pas redimensionnable, l'opération de suppression et d'ajout doit ne pas être prise en charge.

4
Andreas_D

Arrays.asList () renvoie une liste qui n'autorise pas les opérations affectant sa taille (notez que ce n'est pas la même chose que "non modifiable").

Vous pouvez faire new ArrayList<String>(Arrays.asList(split)); pour créer une copie réelle, mais, vu ce que vous essayez de faire, voici une suggestion supplémentaire (vous avez un algorithme O(n^2) juste en dessous).

Vous voulez supprimer list.size() - count (appelons cela k) des éléments aléatoires de la liste. Il vous suffit de choisir autant d’éléments aléatoires et de les permuter aux positions k finales de la liste, puis de supprimer toute cette plage (par exemple, en utilisant subList () et clear ()). Cela le transformerait en un algorithme maigre et moyen O(n) (O(k) est plus précis).

Mise à jour: Comme indiqué ci-dessous, cet algorithme n'a de sens que si les éléments ne sont pas ordonnés, par exemple. si la liste représente un sac. Si, par contre, la liste a un ordre significatif, cet algorithme ne le conservera pas (l'algorithme des polygélélubrifiants le ferait à la place).

Mise à jour 2: Donc, rétrospectivement, un meilleur algorithme (linéaire, en maintenant l'ordre, mais avec O(n) nombres aléatoires) ressemblerait à ceci:

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--;
  }
}
4
Dimitris Andreou

J'ai une autre solution à ce problème:

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

travailler sur newList;)

3
ZZ 5

Cette exception UnsupportedOperationException survient lorsque vous essayez d'effectuer une opération sur une collection où ce n'est pas autorisé. Dans votre cas, lorsque vous appelez Arrays.asList, il ne retourne pas Java.util.ArrayList. Il retourne un Java.util.Arrays$ArrayList qui est une liste immuable. Vous ne pouvez pas y ajouter et vous ne pouvez pas en retirer.

2
Mayank Gupta

Oui, sur Arrays.asList, renvoyant une liste de taille fixe.

Outre l’utilisation d’une liste chaînée, utilisez simplement la liste de méthodes addAll.

Exemple:

String idList = "123,222,333,444";

List<String> parentRecepeIdList = new ArrayList<String>();

parentRecepeIdList.addAll(Arrays.asList(idList.split(","))); 

parentRecepeIdList.add("555");
2
Sameer Kazi

Liste des auteurs = Tableaux.asList (); // Retourne arraylist immuable Pour rendre la solution modifiable, il faudrait: Arraylist narraylist = new ArrayList (Arrays.asList ());

1
BruceWayne

Vous ne pouvez pas supprimer ni ajouter à une liste de tableaux à taille fixe.

Mais vous pouvez créer votre sous-liste à partir de cette liste.

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

* L'autre façon est

ArrayList<String> al = new ArrayList<String>(Arrays.asList(template));

cela va créer ArrayList qui n’a pas une taille fixe comme Arrays.asList

1
Venkat

Remplacer

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

à

List<String> list = New ArrayList<>();
list.addAll(Arrays.asList(split));

ou

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

ou

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

ou (Mieux pour Supprimer des éléments)

List<String> list = new LinkedList<>(Arrays.asList(split));
1
Karthik Kompelli

Voici un extrait de code provenant de tableaux

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;

ainsi, lorsque la méthode asList est appelée, elle renvoie la liste de sa propre version de classe statique privée, qui ne remplace pas add funcion de AbstractList pour stocker un élément dans un tableau. Donc, par défaut, ajouter une méthode dans une liste abstraite lève une exception.

Donc, ce n'est pas une liste de tableaux régulière.

1
Gagandeep Singh

Arrays.asList() utilise un tableau de taille fixe en interne.
Vous ne pouvez pas ajouter ou supprimer dynamiquement de thisArrays.asList()

Utilisez ceci

Arraylist<String> narraylist=new ArrayList(Arrays.asList());

Dans narraylist, vous pouvez facilement ajouter ou supprimer des éléments.

0
Roushan Kumar