Java List.add()UnsupportedOperationException


225

オブジェクトを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(Unknown Source)
    java.util.AbstractList.add(Unknown Source)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:641)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:722)

回答:


457

すべてのList実装がadd()メソッドをサポートしているわけではありません。

一般的な例の1つは、次のようにList返されます。構造の変更(つまり、要素の削除または追加)をサポートしないArrays.asList()ことが文書化されています(強調は私のものです)。

指定された配列を基にする固定サイズのリストを返します。

それListが変更しようとしている特定のものではない場合でも、その答えListは、不変であるか、選択された一部の変更のみを許可する他の実装にも適用されます。

これについては、「(オプションの操作)」であると記載されているUnsupportedOperationExceptionおよびのドキュメントを参照してList.add()ください。このフレーズの正確な意味は、Listドキュメントの上部で説明されています。

回避策として、次のような既知の変更可能な実装にリストのコピーを作成できますArrayList

seeAlso = new ArrayList<>(seeAlso);

1
それで、要素を追加する必要があるときに、リストインスタンスを使用して、要素と配列インスタンスが含まれているかどうかをテストする必要がありますか?書いてる?
FAjir

90
@Florito:これでも機能します:List<String> listMembres = new ArrayList<String>(Arrays.asList(tabMembres));:)
mre

または多分私は自分のリストオブジェクトをArrayListまたは別のものにキャストする必要がありますか?
FAjir

2
いいえ、そうではありません。追加をList許可しない実装に要素を追加する場合は、それをListArrayList一般的な候補である)実装にコピーして、それに追加する必要があります。
ヨアヒムザウアー

8

List実装の多くは、追加/削除のサポートに制限があり、Arrays.asList(membersArray)はその1つです。java.util.ArrayListにレコードを挿入するか、以下の方法を使用してArrayListに変換する必要があります。

コードの最小限の変更で、以下を実行してリストをArrayListに変換できます。最初のソリューションはソリューションの変更を最小限に抑えていますが、2番目のソリューションはより最適化されていると思います。

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

4

継承の概念を形成します。特定のメソッドが現在のクラスで利用できない場合、スーパークラスでそのメソッドを検索します。利用可能な場合は実行されます。

スローするAbstractList<E>クラス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<E>クラスadd()関数を実行しUnsupportedOperationExceptionます。

なので AbstractList<E>抽象クラスとに、それはへの実装を提供し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.unmodifiableList(list);

サンプルソース:

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

Collectionコンテナとも呼ばれる)は、複数の要素を1つの単位にグループ化するオブジェクトです。コレクションは、集計データの保存、取得、操作、通信に使用されます。

@seeも


3

リストを初期化する必要がありますseeAlso:

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

または

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

2
初期化されていない変数が原因UnsupportedOperationExceptionで発生することはありませんadd()。代わりにNPEを取得します。
スティーブンC

0

リストmembersList = Arrays.asList(membersArray);

不変のリストを返す、あなたがする必要があるのは

新しいArrayList <>(Arrays.asList(membersArray)); 変更可能にする


不変のリストではありません。リストの長さを変更しない変異操作がサポートされています/動作します。重要なことは、リストの長さが変更できない配列...に支えられているため、リストの長さが変更できないことです。
スティーブンC

-1

add()を使用する代わりに、addall()を使用できます

{ seeAlso.addall(groupDn); }

addは単一の項目を追加し、addAllはコレクションの各項目を1つずつ追加します。最後に、コレクションが変更されている場合、両方のメソッドはtrueを返します。ArrayListの場合、コレクションは常に変更されるため、これは取るに足らないことですが、追加される項目が既にそこにある場合、Setなどの他のコレクションはfalseを返すことがあります。


-3

LDAPクエリの結果は変更できません。あなたの問題はこの行にあります:

seeAlso.add(groupDn);

seeAlsoリストは変更できません。


1
問題はそのためではありませんが、Joachimが上で指摘したように、add()をサポートしない可能性のあるListの実装に関係しています。
Liv
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.