Java List.add () UnsupportedOperationException

225

Intento agregar objetos a una List<String>instancia pero arroja un UnsupportedOperationException. ¿Alguien sabe por qué?

Mi código 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);
    }
}

El mensaje de error:

java.lang.UnsupportedOperationException
    java.util.AbstractList.add (fuente desconocida)
    java.util.AbstractList.add (fuente desconocida)
    javax.servlet.http.HttpServlet.service (HttpServlet.java:641)
    javax.servlet.http.HttpServlet.service (HttpServlet.java:722)
FAjir
fuente

Respuestas:

457

No todas las Listimplementaciones admiten el add()método.

Un ejemplo común es el que Listdevuelve Arrays.asList(): está documentado para no admitir ninguna modificación estructural (es decir, eliminar o agregar elementos) (énfasis mío):

Devuelve una lista de tamaño fijo respaldada por la matriz especificada.

Incluso si ese no es el específico Listque está tratando de modificar, la respuesta aún se aplica a otras Listimplementaciones que son inmutables o solo permiten algunos cambios seleccionados.

Puede averiguar sobre esto leyendo la documentación de UnsupportedOperationExceptiony List.add(), que documenta que se trata de una "(operación opcional)". El significado preciso de esta frase se explica en la parte superior de la Listdocumentación.

Como solución alternativa, puede crear una copia de la lista en una implementación modificable conocida como ArrayList:

seeAlso = new ArrayList<>(seeAlso);
Joachim Sauer
fuente
1
¿Entonces tengo que usar la instancia de lista para probar si contiene mi elemento y la instancia de matriz cuando tengo que agregar un elemento? ¿eso es escribir?
FAjir
90
@Florito: Esto funcionará: List<String> listMembres = new ArrayList<String>(Arrays.asList(tabMembres));:)
mre
o tal vez tengo que lanzar mi objeto List a ArrayList u otro?
FAjir
2
No en realidad no. Si desea agregar un elemento a una Listimplementación que no permite la adición, deberá copiarlo Listen una implementación que sí lo haga ( ArrayListes un candidato común) y agregarlo.
Joachim Sauer
8

Muchas de las implementaciones de List admiten un soporte limitado para agregar / eliminar, y Arrays.asList (membersArray) es uno de esos. Debe insertar el registro en java.util.ArrayList o usar el siguiente enfoque para convertirlo en ArrayList.

Con el mínimo cambio en su código, puede hacer lo siguiente para convertir una lista a ArrayList. La primera solución es tener un cambio mínimo en su solución, pero la segunda está más optimizada, supongo.

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

O

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

Forme el concepto de herencia, si algún método perticular no está disponible en la clase actual, buscará ese método en superclases. Si está disponible, se ejecuta.

Ejecuta el método de AbstractList<E>clase add()que arroja UnsupportedOperationException.


Cuando está convirtiendo de una matriz a una colección Obejct. es decir, basado en matriz a API basada en colección, entonces le proporcionará un objeto de colección de tamaño fijo, porque el comportamiento de la matriz es de tamaño fijo.

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

Muestras de salsa para conformación.

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> {
        //...
    }
}

Forma la fuente anterior, puedes observar que la java.util.Arrays.ArrayListclase no @Override add(index, element), set(index, element), remove(index). Por lo tanto, de la herencia se ejecuta súper AbstractList<E>clase de add()función que lanza UnsupportedOperationException.

Como AbstractList<E>es una clase abstracta, proporciona la implementación a iterator() and listIterator(). Entonces, podemos iterar sobre el objeto de la lista.

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());

Incluso puede crear la clase de forma de matriz de tamaño fijo. Collections.unmodifiableList(list);

Fuente de muestra:

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

A Collection, a veces llamado contenedor, es simplemente un objeto que agrupa múltiples elementos en una sola unidad. Las colecciones se utilizan para almacenar, recuperar, manipular y comunicar datos agregados.

@ver también

Yash
fuente
3

Debe inicializar su Lista, vea también:

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

o

List<String> seeAlso = new ArrayList<String>();
dwayne
fuente
2
Una variable no inicializada no causará UnsupportedOperationExceptionen add(). En su lugar, obtendría un NPE.
Stephen C
0

Lista membersList = Arrays.asList (membersArray);

devuelve una lista inmutable, lo que debe hacer es

nueva ArrayList <> (Arrays.asList (membersArray)); para hacerlo mutable

Ziv.Ti
fuente
No es una lista inmutable. Las operaciones de mutación que no cambian la longitud de la lista son compatibles / funcionarán. La clave es que la longitud de la lista no puede cambiar porque la lista está respaldada por una matriz ... cuya longitud no puede cambiar.
Stephen C
-1

en lugar de usar add () podemos usar addall ()

{ seeAlso.addall(groupDn); }

add agrega un solo elemento, mientras que addAll agrega cada elemento de la colección uno por uno. Al final, ambos métodos devuelven verdadero si la colección ha sido modificada. En el caso de ArrayList, esto es trivial, porque la colección siempre se modifica, pero otras colecciones, como Set, pueden devolver false si los elementos que se agregan ya están allí.

Allen
fuente
-3

No puede modificar un resultado de una consulta LDAP. Tu problema está en esta línea:

seeAlso.add(groupDn);

La lista seeAlso también es inmodificable.

nfechner
fuente
1
el problema no se debe a eso, pero como Joachim señaló anteriormente, tiene que ver con implementaciones de List que podrían no ser compatibles con add ().
Liv