Pourquoi est-ce que j'obtiens une exception UnsupportedOperationException quand j'essaie 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'obtiens ceci:

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 manière? Java.15

361
demandé sur Pang 2010-06-03 16:08:43

12 réponses

pas mal de problèmes avec votre code:

Sur Arrays.asList retour d'une taille fixe la liste

de L'API:

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

Vous ne pouvez pas add ; vous ne pouvez pas remove . Vous ne pouvez pas modifier la structure du List .

Fix

créer un LinkedList , qui prend en charge plus rapide remove .

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

Sur split en prenant l'expression rationnelle

de L'API:

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

| est un metacharacter regex; si vous voulez vous séparer sur un | littéral , vous devez l'échapper à \| , qui comme une chaîne de caractères Java littéral est "\|" .

Correction:

template.split("\|")

Sur les mieux "algorithme 1519230920"

au lieu d'appeler remove un à la fois avec des indices aléatoires, il est préférable de générer assez de nombres aléatoires dans la gamme, puis en traversant le List une fois avec un listIterator() , 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 gamme donnée.

avec ceci, votre algorithme serait O(N) .

799
répondu polygenelubricants 2010-06-03 12:19:15

celui-ci m'a brûlé plusieurs fois. Arrays.asList crée une liste non modifiable. Depuis le Javadoc: renvoie une liste fixe-size appuyée par le tableau spécifié.

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

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

cela va créer un peu de déchets supplémentaires, mais vous serez en mesure de le muter.

110
répondu Nick Orton 2012-10-01 16:03:43

probablement parce que vous travaillez avec enveloppe non modifiable .

modifier la ligne:

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

sur cette ligne:

List<String> list = new LinkedList<>(Arrays.asList(split));
40
répondu Roman 2017-06-12 20:40:43

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.

9
répondu Salim Hamidi 2016-10-24 18:29:52

vient de lire le JavaDoc pour la méthode asList:

renvoie une {@liste de codes} des objets dans le tableau spécifié. La taille de la {@liste de codes} ne peut pas être modifiée, c'est à dire l'ajout et la suppression sont sans support, mais les éléments peuvent être définir. Définir un élément modifie sous-jacent tableau.

c'est de Java 6 mais il semble que c'est la même chose pour l'android java.

EDIT

le type de la liste résultante est Arrays.ArrayList , qui est une classe privée à l'intérieur des tableaux.classe. Pratiquement parlant, ce n'est rien d'autre qu'une vue de liste sur le tableau que vous avez passé avec Arrays.asList . Avec une conséquence: si vous modifiez le tableau, la liste est aussi changé. Et parce qu'un tableau n'est pas redimensionnable, supprimer et ajouter l'opération doit être non supportée.

4
répondu Andreas_D 2010-06-03 12:30:03
Tableaux

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

vous pouvez faire new ArrayList<String>(Arrays.asList(split)); pour créer une vraie copie, mais en voyant 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 ) éléments aléatoires de la liste. Il suffit de choisir autant au hasard les éléments et les échanger à la fin k les positions de la liste, puis supprimer l'ensemble de la gamme (par exemple à l'aide de sous-liste() et clear ()). Cela le transformerait en un algorithme simple et moyen O(n) ( O(k) est plus précis).

Update : comme indiqué ci-dessous, cet algorithme n'a de sens que si les éléments ne sont pas Classés, par exemple si la liste représente un sac. Si, d'autre part, la Liste a un ordre significatif, cet algorithme ne serait pas préservez - le (l'algorithme de polygenelubricants le ferait).

mise à jour 2 : ainsi, rétrospectivement, un meilleur(linéaire, maintien de l'ordre, mais avec O (n) nombres aléatoires) algorithme serait quelque chose comme 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
répondu Dimitris Andreou 2010-06-03 13:03:53

la liste retournée par Arrays.asList() pourrait être immuable. Pouvez-vous essayer

List<String> list = new ArrayList(Arrays.asList(split));
4
répondu Pierre 2017-06-12 20:41:20

j'ai une autre solution pour ce problème:

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

le travail newList ;)

3
répondu ZZ 5 2017-06-12 20:40:58

cette exception de fonctionnement non supportée vient quand vous essayez d'effectuer une opération sur la collecte où son pas autorisé et dans votre cas, quand vous appelez Arrays.asList il ne renvoie pas un java.util.ArrayList . Il renvoie une java.util.Arrays$ArrayList qui est une liste immuable. Vous ne pouvez pas ajouter d'elle et vous ne pouvez pas supprimer.

2
répondu Mayank Gupta 2010-06-03 13:30:40

Oui, sur Arrays.asList , de retour d'une taille fixe la liste.

autre que l'utilisation d'une liste liée, il suffit d'utiliser addAll liste de méthode.

exemple:

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

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

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

parentRecepeIdList.add("555");
2
répondu Sameer Kazi 2017-06-12 20:42:22

ci-dessous est un extrait de code 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;

donc ce qui se passe, c'est que lorsque la méthode asList est appelée, elle renvoie la liste de sa propre version privée de classe statique qui ne supplante pas add funcion from AbstractList pour stocker l'élément dans array. Ainsi par défaut ajoute la méthode dans la liste abstraite jette l'exception.

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

1
répondu Gagandeep Singh 2016-04-15 04:10:13

vous ne pouvez pas supprimer, ni ajouter à une liste de tableaux de 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, ", ");
}

*d'Autres, c'est "la 151940920"

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

cela créera ArrayList qui n'est pas de taille fixe comme les tableaux.asList

1
répondu Venkat 2017-06-12 20:42:09