Java List.add () UnsupportedOperationException

225

Eu tento adicionar objetos a uma List<String>instância, mas lança um UnsupportedOperationException. Alguem sabe por quê?

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

A mensagem de erro:

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

Respostas:

457

Nem toda Listimplementação suporta o add()método.

Um exemplo comum é o Listretornado por Arrays.asList(): está documentado para não suportar nenhuma modificação estrutural (isto é, remover ou adicionar elementos) (ênfase minha):

Retorna uma lista de tamanho fixo apoiada pela matriz especificada.

Mesmo que esse não seja o específico que Listvocê está tentando modificar, a resposta ainda se aplica a outras Listimplementações imutáveis ​​ou que permitem apenas algumas alterações selecionadas.

Você pode descobrir isso lendo a documentação de UnsupportedOperationExceptione List.add(), que documenta isso como uma "(operação opcional)". O significado preciso dessa frase é explicado na parte superior da Listdocumentação.

Como solução alternativa, você pode criar uma cópia da lista para uma implementação modificável conhecida como ArrayList:

seeAlso = new ArrayList<>(seeAlso);
Joachim Sauer
fonte
1
então eu tenho que usar a instância da lista para testar se ele contém o meu elemento e a instância da matriz quando eu tenho que adicionar um elemento? isso é escrever?
precisa saber é o seguinte
90
@Florito: Isto irá funcionar no entanto: List<String> listMembres = new ArrayList<String>(Arrays.asList(tabMembres));:)
MRE
ou talvez eu precise converter meu objeto List para ArrayList ou outro?
precisa saber é o seguinte
2
Não, na verdade não. Se você deseja adicionar um elemento a uma Listimplementação que não permite adição, precisará copiá-lo Listpara uma implementação que faz ( ArrayListé um candidato comum) e adicionar a isso.
Joachim Sauer
8

Muitas das implementações da Lista oferecem suporte limitado para adicionar / remover, e o Arrays.asList (membersArray) é um deles. Você precisa inserir o registro em java.util.ArrayList ou usar a abordagem abaixo para converter em ArrayList.

Com a alteração mínima no seu código, você pode fazer abaixo para converter uma lista em ArrayList. A primeira solução é ter uma alteração mínima na sua solução, mas a segunda é mais otimizada, eu acho.

    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
fonte
4

Forme o conceito de herança. Se algum método perticular não estiver disponível na classe atual, ele buscará esse método nas superclasses. Se disponível, ele é executado.

Ele executa o método de AbstractList<E>classe add()que lança UnsupportedOperationException.


Quando você está convertendo de uma matriz para um objeto de coleção. ou seja, com base em array para API baseada em coleção, ele fornecerá um objeto de coleção de tamanho fixo, porque o comportamento da matriz é de tamanho fixo.

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

Amostras de molho para conformação.

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

Forme a fonte acima, você pode observar que a java.util.Arrays.ArrayListclasse não @Override add(index, element), set(index, element), remove(index). Portanto, a partir da herança, ele executa a função de super AbstractList<E>classe add()que lança UnsupportedOperationException.

Como AbstractList<E>é uma classe abstrata, ela fornece a implementação iterator() and listIterator(). Assim, podemos iterar sobre o objeto da 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());

Você pode até criar um array de tamanho fixo na classe Collections Collections.unmodifiableList(list);

Fonte da amostra:

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- às vezes chamado de contêiner - é simplesmente um objeto que agrupa vários elementos em uma única unidade. As coleções são usadas para armazenar, recuperar, manipular e comunicar dados agregados.

@Veja também

Yash
fonte
3

Você deve inicializar sua lista, ver também:

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

ou

List<String> seeAlso = new ArrayList<String>();
dwayne
fonte
2
Uma variável não inicializada não causará UnsupportedOperationExceptionin add(). Você receberia um NPE.
Stephen C
0

Lista membersList = Arrays.asList (membersArray);

retorna uma lista imutável, o que você precisa fazer é

novo ArrayList <> (Arrays.asList (membersArray)); para torná-lo mutável

Ziv.Ti
fonte
Não é uma lista imutável. As operações de mutação que não alteram o tamanho da lista são suportadas / irão funcionar. O principal é que o comprimento da lista não pode ser alterado porque a lista é apoiada por uma matriz ... cujo comprimento não pode ser alterado.
Stephen C
-1

em vez de usar add (), podemos usar addall ()

{ seeAlso.addall(groupDn); }

add adiciona um único item, enquanto addAll adiciona cada item da coleção, um por um. No final, os dois métodos retornam true se a coleção foi modificada. No caso de ArrayList, isso é trivial, porque a coleção é sempre modificada, mas outras coleções, como Set, podem retornar false se os itens adicionados já estiverem lá.

Allen
fonte
-3

Você não pode modificar um resultado de uma consulta LDAP. Seu problema está nesta linha:

seeAlso.add(groupDn);

A lista seeAlso não pode ser modificada.

nfechner
fonte
1
o problema não se deve a isso, mas, como Joachim apontou acima, tem a ver com implementações da List que podem não suportar add ().
22411 Liv