【问题标题】:Java List.add() UnsupportedOperationExceptionJava List.add() UnsupportedOperationException
【发布时间】:2011-08-10 23:02:21
【问题描述】:

我尝试将对象添加到 List<String> 实例,但它会抛出 UnsupportedOperationException。 有谁知道为什么?

我的 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);
    }
}

错误信息:

java.lang.UnsupportedOperationException java.util.AbstractList.add(未知来源) java.util.AbstractList.add(未知来源) javax.servlet.http.HttpServlet.service(HttpServlet.java:641) javax.servlet.http.HttpServlet.service(HttpServlet.java:722)

【问题讨论】:

    标签: java list exception arraylist unsupportedoperation


    【解决方案1】:

    并非每个List 实现都支持add() 方法。

    一个常见的例子是Arrays.asList() 返回的List:它被记录为支持任何结构修改(即删除或添加元素)(强调我的):

    返回由指定数组支持的固定大小列表。

    即使这不是您尝试修改的特定 List,答案仍然适用于其他不可变或仅允许某些选定更改的 List 实现。

    您可以通过阅读UnsupportedOperationExceptionList.add() 的文档来了解这一点,这些文档将其记录为“(可选操作)”。这个短语的确切含义在List 文档的顶部进行了解释。

    作为一种解决方法,您可以将列表的副本创建到已知的可修改实现,例如 ArrayList

    seeAlso = new ArrayList<>(seeAlso);
    

    【讨论】:

    • 所以当我必须添加一个元素时,我必须使用列表实例来测试它是否包含我的元素和数组实例?这是写的?
    • @Florito:这会起作用:List&lt;String&gt; listMembres = new ArrayList&lt;String&gt;(Arrays.asList(tabMembres)); :)
    • 或者我必须将我的 List 对象转换为 ArrayList 或其他?
    • 不,不是。如果您想将一个元素添加到不允许添加的List 实现,那么您必须将该List 复制到一个实现(ArrayList 是一个常见的候选)并添加到那个。
    【解决方案2】:

    许多 List 实现支持有限的添加/删除支持,Arrays.asList(membersArray) 就是其中之一。需要在 java.util.ArrayList 中插入记录或者使用下面的方法转换成 ArrayList。

    通过对代码进行最小的更改,您可以执行以下操作将列表转换为 ArrayList。第一个解决方案对您的解决方案进行了最小的更改,但我猜第二个解决方案更优化。

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

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

    【讨论】:

      【解决方案3】:

      形成继承概念,如果某些特定方法在当前类中不可用,它将在超类中搜索该方法。如果可用,它会执行。

      它执行AbstractList&lt;E&gt;add()方法抛出UnsupportedOperationException


      当您从数组转换为集合对象时。即,基于数组的 API 到基于集合的 API,那么它将为您提供固定大小的集合对象,因为 Array 的行为是固定大小的。

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

      为构象提供样品。

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

      形成上述来源,您可能会发现java.util.Arrays.ArrayList 类不是@Override add(index, element), set(index, element), remove(index)。因此,从继承中它执行超级 AbstractList&lt;E&gt;add() 函数,该函数抛出 UnsupportedOperationException

      由于AbstractList&lt;E&gt; 是一个抽象类,它为iterator() and listIterator() 提供了实现。所以,我们可以遍历列表对象。

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

      您甚至可以从 Collections 类Collections.unmodifiableList(list); 中创建 Fixed-Size 数组

      样本来源:

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

      Collection(有时称为容器)只是一个将多个元素组合成一个单元的对象。集合用于存储、检索、操作和交流聚合数据。

      @另见

      【讨论】:

        【解决方案4】:

        List membersList = Arrays.asList(membersArray);

        返回不可变列表,你需要做的是

        new ArrayList(Arrays.asList(membersArray));使其可变

        【讨论】:

        • 它不是一个不可变的列表。不改变列表长度的变异操作受支持/将起作用。关键是列表的长度不能改变,因为列表是由一个数组支持的......其长度不能改变。
        【解决方案5】:

        如果您尝试将add 转换为由Collections.singletonList(T o) 返回的List&lt;T&gt;,也会出现此异常:

        返回一个只包含指定对象的不可变列表。返回的列表是可序列化的。

        JVM 没有为Collections.singletonList 实现add()

        【讨论】:

        【解决方案6】:

        你必须初始化你的 List 另见:

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

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

        【讨论】:

        • 未初始化的变量不会在add() 中导致UnsupportedOperationException。你会得到一个 NPE。
        【解决方案7】:

        您不能修改 LDAP 查询的结果。您的问题出在这一行:

        seeAlso.add(groupDn);
        

        seeAlso 列表不可修改。

        【讨论】:

        • 问题不是因为这个,而是正如 Joachim 在上面指出的那样,它与可能不支持 add() 的 List 的实现有关。
        【解决方案8】:

        我们可以使用 addall() 来代替 add()

        { seeAlso.addall(groupDn); }
        

        add 添加单个项目,而 addAll 将集合中的每个项目逐一添加。最后,如果集合已被修改,这两种方法都会返回 true。在 ArrayList 的情况下,这是微不足道的,因为集合总是被修改,但如果要添加的项目已经存在,其他集合(例如 Set)可能会返回 false。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-01-14
          • 2018-01-04
          • 2015-12-31
          • 1970-01-01
          • 1970-01-01
          • 2020-04-13
          • 2018-04-27
          相关资源
          最近更新 更多