Java List.add () UnsupportedOperationException

225

J'essaie d'ajouter des objets à une List<String>instance mais cela lance un UnsupportedOperationException. Quelqu'un sait-il pourquoi?

Mon code Java:

String[] membersArray = request.getParameterValues('members');
List<String> membersList = Arrays.asList(membersArray);

for (String member : membersList) {
    Person person = Dao.findByName(member);
    List<String> seeAlso;
    seeAlso = person.getSeeAlso();
    if (!seeAlso.contains(groupDn)){
        seeAlso.add(groupDn);
        person.setSeeAlso(seeAlso);
    }
}

Le message d'erreur:

java.lang.UnsupportedOperationException
    java.util.AbstractList.add (Source inconnue)
    java.util.AbstractList.add (Source inconnue)
    javax.servlet.http.HttpServlet.service (HttpServlet.java:641)
    javax.servlet.http.HttpServlet.service (HttpServlet.java:722)
FAjir
la source

Réponses:

457

Toutes les Listimplémentations ne prennent pas en charge la add()méthode.

Un exemple courant est le Listretourné par Arrays.asList(): il est documenté qu'il ne prend en charge aucune modification structurelle (c'est-à-dire en supprimant ou en ajoutant des éléments) (c'est moi qui souligne):

Renvoie une liste de taille fixe soutenue par le tableau spécifié.

Même si ce n'est pas le spécifique Listque vous essayez de modifier, la réponse s'applique toujours aux autres Listimplémentations qui sont soit immuables, soit autorisent uniquement certaines modifications sélectionnées.

Vous pouvez vous renseigner à ce sujet en lisant la documentation de UnsupportedOperationExceptionet List.add(), qui documente qu'il s'agit d'un "(opération facultative)". La signification précise de cette phrase est expliquée en haut de la Listdocumentation.

Comme solution de contournement, vous pouvez créer une copie de la liste vers une implémentation modifiable connue comme ArrayList:

seeAlso = new ArrayList<>(seeAlso);
Joachim Sauer
la source
1
donc je dois utiliser l'instance de liste pour tester si elle contient mon élément et l'instance de tableau quand je dois ajouter un élément? c'est écrire?
FAjir
90
@Florito: Cela fonctionnera cependant: List<String> listMembres = new ArrayList<String>(Arrays.asList(tabMembres));:)
mre
ou peut-être dois-je convertir mon objet List en ArrayList ou autre?
FAjir
2
Non, pas vraiment. Si vous souhaitez ajouter un élément à une Listimplémentation qui ne permet pas l'ajout, vous devrez le copier Listdans une implémentation qui le fait ( ArrayListest un candidat courant) et y ajouter.
Joachim Sauer
8

De nombreuses implémentations de la liste prennent en charge la prise en charge limitée de l'ajout / suppression, et Arrays.asList (membersArray) en fait partie. Vous devez insérer l'enregistrement dans java.util.ArrayList ou utiliser l'approche ci-dessous pour convertir en ArrayList.

Avec la modification minimale de votre code, vous pouvez faire ci-dessous pour convertir une liste en ArrayList. La première solution est d'avoir un changement minimum dans votre solution, mais la seconde est plus optimisée, je suppose.

    String[] membersArray = request.getParameterValues('members');
    ArrayList<String> membersList = new ArrayList<>(Arrays.asList(membersArray));

OU

    String[] membersArray = request.getParameterValues('members');
    ArrayList<String> membersList = Stream.of(membersArray).collect(Collectors.toCollection(ArrayList::new));
krmanish007
la source
4

Formez le concept d'héritage, si une méthode perticulaire n'est pas disponible dans la classe actuelle, elle recherchera cette méthode dans les super classes. S'il est disponible, il s'exécute.

Il exécute AbstractList<E>la add()méthode de classe qui lance UnsupportedOperationException.


Lorsque vous convertissez un tableau en un objet de collection. c'est-à-dire, basé sur un tableau vers une API basée sur une collection, il vous fournira un objet de collection de taille fixe, car le comportement d'Array est de taille fixe.

java.util.Arrays.asList (T ... a)

Échantillons de Souce pour la conformation.

public class Arrays {
    public static <T> List<T> asList(T... a) {
        return new java.util.Arrays.ArrayList.ArrayList<>(a); // Arrays Inner Class ArrayList
    }
    //...
    private static class ArrayList<E> extends AbstractList<E> implements RandomAccess, java.io.Serializable {
        //...
    }
}
public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
    public void add(int index, E element) {
        throw new UnsupportedOperationException();
    }
    public E set(int index, E element) {
        throw new UnsupportedOperationException();
    }
    public E remove(int index) {
        throw new UnsupportedOperationException();
    }

    public Iterator<E> iterator() {
        return new Itr();
    }
    private class Itr implements Iterator<E> {
        //...
    }

    public ListIterator<E> listIterator() {
        return listIterator(0);
    }
    private class ListItr extends Itr implements ListIterator<E> {
        //...
    }
}

Formez la source ci-dessus, vous remarquerez que la java.util.Arrays.ArrayListclasse ne le fait pas @Override add(index, element), set(index, element), remove(index). Donc, à partir de l'héritage, il exécute une fonction de super AbstractList<E>classe add()qui lance UnsupportedOperationException.

Comme AbstractList<E>c'est une classe abstraite, elle fournit l'implémentation à iterator() and listIterator(). Donc, que nous pouvons itérer sur l'objet liste.

List<String> list_of_Arrays = Arrays.asList(new String[] { "a", "b" ,"c"});

try {
    list_of_Arrays.add("Yashwanth.M");
} catch(java.lang.UnsupportedOperationException e) {
    System.out.println("List Interface executes AbstractList add() fucntion which throws UnsupportedOperationException.");
}
System.out.println("Arrays → List : " + list_of_Arrays);

Iterator<String> iterator = list_of_Arrays.iterator();
while (iterator.hasNext()) System.out.println("Iteration : " + iterator.next() );

ListIterator<String> listIterator = list_of_Arrays.listIterator();
while (listIterator.hasNext())    System.out.println("Forward  iteration : " + listIterator.next() );
while(listIterator.hasPrevious()) System.out.println("Backward iteration : " + listIterator.previous());

Vous pouvez même créer une classe Collections sous forme de tableau à taille fixe Collections.unmodifiableList(list);

Exemple de source:

public class Collections {
    public static <T> List<T> unmodifiableList(List<? extends T> list) {
        return (list instanceof RandomAccess ?
                new UnmodifiableRandomAccessList<>(list) :
                new UnmodifiableList<>(list));
    }
}

Un Collection- parfois appelé conteneur - est simplement un objet qui regroupe plusieurs éléments en une seule unité. Les collections sont utilisées pour stocker, récupérer, manipuler et communiquer des données agrégées.

@voir également

Yash
la source
3

Vous devez initialiser votre liste voir également:

List<String> seeAlso = new Vector<String>();

ou

List<String> seeAlso = new ArrayList<String>();
dwayne
la source
2
Une variable non initialisée ne provoquera pas UnsupportedOperationExceptionde add(). Vous obtiendriez un NPE à la place.
Stephen C
0

List membersList = Arrays.asList (membersArray);

renvoie une liste immuable, ce que vous devez faire est

new ArrayList <> (Arrays.asList (membersArray)); pour le rendre mutable

Ziv.Ti
la source
Ce n'est pas une liste immuable. Les opérations de mutation qui ne modifient pas la longueur de la liste sont prises en charge / fonctionneront. L'essentiel est que la longueur de la liste ne puisse pas changer car la liste est soutenue par un tableau ... dont la longueur ne peut pas changer.
Stephen C
-1

au lieu d'utiliser add (), nous pouvons utiliser addall ()

{ seeAlso.addall(groupDn); }

add ajoute un seul élément, tandis que addAll ajoute chaque élément de la collection un par un. Au final, les deux méthodes renvoient true si la collection a été modifiée. Dans le cas d'ArrayList, cela est trivial, car la collection est toujours modifiée, mais d'autres collections, telles que Set, peuvent retourner false si les éléments ajoutés sont déjà là.

Allen
la source
-3

Vous ne pouvez pas modifier un résultat d'une requête LDAP. Votre problème est dans cette ligne:

seeAlso.add(groupDn);

La liste seeAlso n'est pas modifiable.

nfechner
la source
1
le problème n'est pas dû à cela, mais comme Joachim l'a souligné ci-dessus, cela concerne les implémentations de List qui ne prennent pas en charge add ().
Liv